聯合索引(複合索引)將多個列按順序組合成一個 B+ 樹索引,結構類似電話簿「先按姓氏排序,同姓氏再按名字排序」。MySQL 優化器遵循最左前綴原則:索引 (a,b,c) 可支持 a、a,b、a,b,c 三種查找組合,但無法直接用於 b、c、b,c 的查詢。
CREATE TABLE test (a INT, b INT, c INT, KEY idx_abc (a,b,c));
建立聯合索引時,區分度高(Cardinality 大)、常用於 WHERE/JOIN/ORDER BY 的列應優先靠左。若查詢頻繁單獨檢索 b 或 c,需額外建立單列索引或調整列序。
聯合索引天然有序,可消耗 Filesort。但需嚴格匹配索引列的順序與方向:
CREATE INDEX idx_ex ON t (col1 ASC, col2 DESC, col3 ASC);
ORDER BY col1 ASC, col2 DESC, col3 ASC(完全一致)ORDER BY col1 DESC, col2 ASC, col3 DESC(完全相反)ORDER BY col1 ASC, col2 ASC, col3 ASC(方向不匹配,觸發 Filesort)若 WHERE 條件固定了前導列為常量,後續列仍可利用索引排序。
優化器根據統計信息估算掃描行數,選擇成本最低的索引。關鍵規則:
WHERE col1=1 AND col2=2 用到 (col1,col2,col3);WHERE col2=2 則無效WHERE col1=1 AND col2>2 AND col3=3 中 col3 無法用到索引name LIKE '張%' 走索引,%張 或 %張% 全表掃描| 場景 | 原因 | 解決方案 |
|---|---|---|
WHERE col != 100 | 不等於操作符導致全表掃描 | 改用 col < 100 OR col > 100(需評估成本) |
WHERE col IS NULL | B+ 樹默認不存 NULL(除位圖索引) | 建表時定義 NOT NULL DEFAULT '' |
WHERE TRUNC(date) = '...' | 索引列上使用函數破壞有序性 | 改寫為範圍查詢:date >= '...' AND date < '...' |
WHERE varchar_col = 123 | 隱式類型轉換觸發函數操作 | 統一使用字符串字面量:varchar_col = '123' |
場景:SELECT id FROM articles WHERE category_id=5 ORDER BY created DESC LIMIT 10
(category_id, created) 即可實現 Covering Index,無需回表(category_id, created, id) 才能覆蓋latin1 或 ascii,索引體積縮減 50%+