t_group:1038 萬行,欄位 id, money, user_name, create_time。user_name 僅 8 個 distinct 值,單列索引基數極低(8),屬「爛索引」。WHERE user_name = 'xxx' 或 <> 'xxx'。DELIMITER $$
CREATE PROCEDURE sp_split_table()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_user_name VARCHAR(20);
DECLARE v_table_name VARCHAR(64);
DECLARE cur1 CURSOR FOR SELECT user_name FROM t_group GROUP BY user_name;
DECLARE CONTINUE HANDLER FOR 1329 SET done = 1;
OPEN cur1;
WHILE done <> 1 DO
FETCH cur1 INTO v_user_name;
IF NOT done THEN
SET v_table_name = CONCAT('t_group_', v_user_name);
SET @stmt = CONCAT('CREATE TABLE ', v_table_name, ' LIKE t_group');
PREPARE s1 FROM @stmt; EXECUTE s1; DEALLOCATE PREPARE s1;
SET @stmt = CONCAT('INSERT INTO ', v_table_name, ' SELECT * FROM t_group WHERE user_name = ''', v_user_name, '''');
PREPARE s1 FROM @stmt; EXECUTE s1; DEALLOCATE PREPARE s1;
END IF;
END WHILE;
CLOSE cur1;
SET @stmt = NULL;
END$$
DELIMITER ;
生成 8 張子表:t_group_david、t_group_leo... 每表約 130 萬行,保留原表結構(含 user_name 冗余列)。
| 查詢 | 原大表 | 分表 | 優化後分表(刪除 user_name) |
|---|---|---|---|
COUNT(*) WHERE user_name='david' | 1.71 秒 | 0.00 秒 | 0.00 秒 |
COUNT(*) WHERE user_name<>'david' | 9.26 秒 | — | (SELECT COUNT(*) FROM t_group) - (SELECT COUNT(*) FROM t_group_david) → 0.00 秒 |
MIN/MAX(money) WHERE user_name='david' | 0.00 秒(全索引掃描) | 1.50 秒(全表掃描) | 0.00 秒(全索引掃描) |
SUM/AVG(money) WHERE user_name='david' | 2.15 秒 | 1.68 秒 | 0.94 秒 |
子表中 user_name 已成常量,刪除該列後:
MIN/MAX 從全表掃描變為全索引掃描(秒級 → 毫秒級)。SUM/AVG 亦顯著加速(1.68s → 0.94s)。