索引是資料庫效能的關鍵,但並非萬能良藥。本文系統梳理 MySQL 索引的類型、適用場景、無法使用的常見陷阱,以及透過 EXPLAIN 進行查詢分析與優化的實戰方法。
索引是特殊檔案(InnoDB 為表空間一部分),包含對資料表所有記錄的引用指標。核心權衡:
MySQL 單表索引上限 16 個。InnoDB 表中索引更關鍵:除加速查詢外,還是行級鎖定機制的基礎——鎖定發生在索引上而非表本身,無適當索引則退化為表鎖,嚴重影響並發。
關鍵字 KEY 或 INDEX 定義,單純加速存取。優先選擇資料分布整齊、緊湊的欄位(如整數類型)。
關鍵字 UNIQUE 定義,保證欄位值唯一。優點:簡化優化器管理、提高效率;自動阻擋重複值寫入。常用於業務主鍵候選欄位(身分證、Email、手機號)。
關鍵字 PRIMARY KEY 定義,表僅能有一個。本質是特殊的唯一索引,InnoDB 以主鍵構建聚簇索引,資料按主鍵順序物理存放。
定義外鍵約束時自動建立內部索引,輔助高效維護參考完整性。
覆蓋多欄位,如 INDEX(columnA, columnB)。遵循最左前綴原則:可用於 columnA 或 (columnA, columnB) 查詢,但無法用於單獨的 columnB 或 (columnB, columnC)。設計時將高選擇性、常用於 WHERE 的欄位置左。
CHAR/VARCHAR:可指定前綴長度(如 INDEX(name(10))),縮小索引體積、提升速度。實務上 10-15 字元通常足夠區分度。BLOB/TEXT:必須指定長度,上限 255 字元。專為大文本欄位設計,建立單詞清單支援自然語言搜尋。語法:MATCH(col1,col2) AGAINST('word1','word2')。注意:InnoDB 5.6 前不支援全文索引。
| 場景 | 範例 | 說明 |
|---|---|---|
| WHERE 條件含不等號 | WHERE column != 'value' | 全表掃描 |
| WHERE 條件對欄位使用函數 | WHERE DAY(date_col) = 1 | 函數破壞索引順序 |
| JOIN 關聯欄位資料型別不一致 | INT JOIN VARCHAR | 隱含轉型導致索引失效 |
| LIKE/REGEXP 以萬用字元開頭 | LIKE '%abc' | 無法利用 B-Tree 順序;LIKE 'abc%' 可用索引 |
| ORDER BY 條件非查詢條件表達式 | WHERE a=1 ORDER BY b | 多表查詢時索引對 ORDER BY 加速效果有限 |
| 欄位重複值極高 | 性別、布林旗標 | 選擇性太低,優化器傾向全表掃描 |
僅在 SELECT 前加 EXPLAIN,MySQL 不執行查詢而是回傳執行計畫。關鍵欄位解讀:
| 欄位 | 含義 | 優化指引 |
|---|---|---|
| table | 讀取順序的表名 | 觀察聯結順序 |
| type | 關聯類型(system > const > eq_ref > ref > range > index > ALL) | 避免 ALL(全表掃描),爭取 ref/range 以上 |
| possible_keys | 理論可用索引 | 若為 NULL,需考慮加索引 |
| key | 實際使用索引 | 確認是否符合預期 |
| key_len | 使用索引長度(位元組) | 越小越好;復合索引可判斷用了幾個欄位 |
| ref | 關聯的另一表欄位或常數 | 觀察聯結依賴 |
| rows | 預估掃描行數 | 所有 rows 乘積 = 總掃描組合數,越小越好 |
| Extra | 額外資訊 | Using index(覆蓋索引佳)、Using temporary(需優化)、Using filesort(排序未用索引) |
possible_keys 與 key。Using index,避免回表。