MEDIUMINT 代替 INT、CHAR 定長優於 VARCHAR、ENUM 代替少量固定值字串。users,37,365 行,username VARCHAR(50)| SQL | 模式 | 平均耗時(秒) | 結果行數 |
|---|---|---|---|
SELECT * FROM users WHERE username LIKE '%許%' | 前後萬用字元 | 0.66 | 960 |
SELECT * FROM users WHERE username LIKE '許%' | 前綴匹配 | 0.53 | 836 |
SELECT * FROM users WHERE username LIKE '%許' | 後綴匹配 | 0.51 | 7 |
CREATE INDEX username_idx ON users(username(6))| SQL | 模式 | 平均耗時(秒) | 結果行數 | 提升倍數 |
|---|---|---|---|---|
LIKE '%許%' | 前後萬用字元 | 0.34 | 960 | 1.9x |
LIKE '許%' | 前綴匹配 | 0.065 | 836 | 8.2x |
LIKE '%許' | 後綴匹配 | 0.31 | 7 | 1.6x |
LIKE 'prefix%' **效果最顯著**(8 倍提升),因 B+Tree 可直接範圍掃描。LIKE '%text%' **索引幫助有限**(仍需掃描大部分索引頁),全文索引或搜尋引擎更適合。EXPLAIN 觀察 rows 最小的表作驅動表(通常是過濾後結果集最小者)。Using index 出現於 Extra。-- 計算前綴選擇性
SELECT
COUNT(DISTINCT LEFT(username, 4)) / COUNT(*) AS sel_4,
COUNT(DISTINCT LEFT(username, 6)) / COUNT(*) AS sel_6,
COUNT(DISTINCT LEFT(username, 8)) / COUNT(*) AS sel_8
FROM users;
-- 選擇選擇性接近 1.0 且長度最短的值
MySQL 支援最長 255 字元(實際受限於 max_key_length 3072 bytes,utf8mb4 每字元 4 bytes → 768 字元)。
-- 單列索引 idx_a(a), idx_b(b)
SELECT * FROM t WHERE a=1 OR b=2; -- 無法合併使用兩個索引,全表掃描
-- 改寫
SELECT * FROM t WHERE a=1
UNION ALL
SELECT * FROM t WHERE b=2 AND a!=1; -- 避免重複,各分支用各自索引
-- IN 值超過幾百個,優化器可能放棄索引改全表掃描
SELECT * FROM t WHERE id IN (1,2,3,...,10000);
-- 改寫:臨時表/値表 JOIN
CREATE TEMPORARY TABLE tmp_ids (id INT PRIMARY KEY);
INSERT INTO tmp_ids VALUES (1),(2),...;
SELECT t.* FROM t JOIN tmp_ids USING(id);
EXPLAIN SELECT ... 觀察 type(目標:ref/range/eq_ref,避免 ALL/index)、key(實際用索引)、rows(預估掃描行)、Extra(Using index/Using where/Using filesort/Using temporary)。EXPLAIN FORMAT=JSON (5.6+) 獲取成本估算 query_cost、read_cost、eval_cost。OPTIMIZER_TRACE 追蹤優化器決策路徑(為何捨棄某索引)。FLUSH STATUS → 執行 → SHOW SESSION STATUS LIKE 'Handler%' 量化 Handler_read_key / Handler_read_rnd_next 變化。MySQL 優化核心是**索引設計匹配查詢模式**。實測證明前綴索引對前綴匹配查詢提升 8 倍,但對任意位置模糊查詢效果有限。掌握 EXPLAIN 深度解讀、複合索引列序決策、IN/OR 改寫技巧、資料類型最小化原則,配合 Performance Schema 量化驗證,才能從經驗主義進入數據驅動優化。記住:**過早優化是萬惡之源,無監控優化是盲人騎瞎馬。**