索引是 MySQL 效能調優的核心。本文系統覆蓋索引類型、儲存引擎差異、優缺點、建立與刪除語法、複合索引最左前綴原則、全文與空間索引、EXPLAIN 執行計劃深度解讀,並提供大量實戰案例。
| 優點 | 缺點 |
| 唯一索引保證資料唯一性 | 寫入 (INSERT/UPDATE/DELETE) 需維護索引,降低寫效能 |
| 大幅加速查詢 (WHERE/JOIN/ORDER BY/GROUP BY) | 佔用磁碟空間,索引檔案可能超過資料檔案 |
| 排序分組避免 filesort | 過多索引導致優化器選擇困難,可能選錯執行計劃 |
二、索引分類與建立語法
2.1 統一建立語法
CREATE TABLE table_name (
col_name data_type,
[UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name [(length)]) [ASC | DESC]
);
INDEX 與 KEY 同義
length 僅適用字串類型 (CHAR/VARCHAR/TEXT/BLOB),指定前綴長度
ASC/DESC MySQL 8.0+ 真正支援降序索引,舊版忽略但語法兼容
2.2 普通索引
CREATE TABLE book (
bookid INT NOT NULL,
bookname VARCHAR(255) NOT NULL,
year_publication YEAR NOT NULL,
INDEX idx_year (year_publication)
);
2.3 唯一索引
CREATE TABLE t1 (
id INT NOT NULL,
name CHAR(30) NOT NULL,
UNIQUE INDEX uniq_idx (id)
);
主鍵 = 唯一索引 + NOT NULL。
2.4 複合索引(聯合索引)
CREATE TABLE t3 (
id INT NOT NULL,
name CHAR(30) NOT NULL,
age INT NOT NULL,
INDEX multi_idx (id, name, age)
);
最左前綴原則:查詢必須從索引最左列開始,才能使用索引。
| 查詢條件 | 是否用到 multi_idx | 說明 |
WHERE id=1 AND name='a' AND age=10 | ✅ 全用 | 最左匹配 |
WHERE id=1 AND name='a' | ✅ 部分用 | 最左匹配 |
WHERE id=1 | ✅ 部分用 | 最左匹配 |
WHERE name='a' | ❌ 不用 | 非最左列開頭 |
WHERE age=10 | ❌ 不用 | 非最左列開頭 |
WHERE name='a' AND age=10 | ❌ 不用 | 缺少最左列 id |
2.5 全文索引
- 類型:
FULLTEXT
- 支援引擎:MyISAM (全版本)、InnoDB (5.6+)
- 適用欄位:CHAR、VARCHAR、TEXT
- 語法:
FULLTEXT INDEX ft_idx (content)
- 查詢:
MATCH(content) AGAINST('keyword' IN NATURAL LANGUAGE MODE)
2.6 空間索引
- 類型:
SPATIAL
- 支援引擎:MyISAM、InnoDB (5.7+)
- 欄位類型:GEOMETRY、POINT、LINESTRING、POLYGON
- 強制
NOT NULL
- 語法:
SPATIAL INDEX spat_idx (geo_col)
三、現有表上建立/刪除索引
3.1 ALTER TABLE
-- 普通索引
ALTER TABLE t1 ADD INDEX idx_name (name);
-- 唯一索引
ALTER TABLE t1 ADD UNIQUE INDEX uniq_email (email);
-- 複合索引
ALTER TABLE t3 ADD INDEX idx_age_info (age, info);
-- 全文索引 (需 MyISAM)
ALTER TABLE t6 ADD FULLTEXT INDEX ft_info (info);
-- 空間索引 (需 NOT NULL + MyISAM/InnoDB 5.7+)
ALTER TABLE t7 ADD SPATIAL INDEX spat_g (g);
3.2 CREATE INDEX
CREATE INDEX idx_bookname ON book (bookname);
CREATE UNIQUE INDEX uniq_bookid ON book (bookid);
CREATE INDEX idx_auth_info ON book (authors(20), info(50));
CREATE FULLTEXT INDEX ft_info ON t6 (info);
CREATE SPATIAL INDEX spat_g ON t7 (g);
3.3 刪除索引
ALTER TABLE book DROP INDEX uniq_bookid;
DROP INDEX idx_auth_info ON book;
注意:AUTO_INCREMENT 欄位的主鍵/唯一索引不可刪除。
3.4 刪除欄位對索引的影響
- 刪除的欄位若為索引組成部分,該欄位從索引中移除
- 若索引所有欄位均被刪除,整個索引自動刪除
四、EXPLAIN 執行計劃深度解讀
4.1 核心欄位含義
| 欄位 | 含義 | 關鍵值解讀 |
| id | SELECT 識別符 | 越大越先執行;相同則按順序 |
| select_type | 查詢類型 | SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION |
| table | 存取的表 | 含衍生表 |
| partitions | 匹配的分區 | 分區表才顯示 |
| type | 存取類型 (最關鍵) | system > const > eq_ref > ref > range > index > ALL |
| possible_keys | 可能用到的索引 | 候選集,不一定被用 |
| key | 實際用到的索引 | NULL 表示全表掃描 |
| key_len | 索引使用長度 (位元組) | 推算複合索引用了幾列 |
| ref | 比較對象 (常數/欄位) | const、func、col_name |
| rows | 預估掃描行數 | 越小越好,統計資訊準確度影響大 |
| filtered | 條件過濾比例% | 100 表示無額外過濾 |
| Extra | 額外資訊 | Using index、Using where、Using temporary、Using filesort |
4.2 type 存取類型詳細解析
system/const -- 系統表/主鍵唯一查找,極快
eq_ref -- 唯一索引/主鍵 JOIN,每行最多一匹配
ref -- 非唯一索引查找/關聯,可能多行
range -- 索引範圍掃描 (>、<、>=、<=、BETWEEN、IN)
index -- 全索引掃描 (覆蓋索引時常見)
ALL -- 全表掃描 (最差,需優化)
4.3 實戰案例分析
EXPLAIN SELECT * FROM t3 WHERE id=1 AND name='小芳';
-- 結果:
-- type=ref, possible_keys=multi_idx, key=multi_idx, key_len=94, ref=const,const, rows=1, Extra=Using where
-- ✅ 使用複合索引,最左匹配 id、name,預估 1 行
EXPLAIN SELECT * FROM t3 WHERE name='小芳';
-- 結果:
-- type=ALL, possible_keys=NULL, key=NULL, rows=2, Extra=Using where
-- ❌ 未用索引,因 name 非最左列
五、索引優化實戰清單
- 慢查詢優先:開啟
slow_query_log,pt-query-digest 分析 Top 10
- EXPLAIN 驗證:關注
type、key、rows、Extra
- 覆蓋索引:
SELECT id, name FROM t WHERE id=1 → INDEX(id, name) 避免回表
- 最左前綴:複合索引列序 = 查詢條件列序 = 排序列序
- 避免索引失效:
- 隱式轉換:
WHERE varchar_col = 123 → WHERE varchar_col = '123'
- 函數運算:
WHERE DATE(created_at) = '2024-01-01' → WHERE created_at >= '2024-01-01' AND created_at < '2024-01-02'
- LIKE 導數:
LIKE '%keyword%' → 全文索引或 LIKE 'keyword%'
- OR 條件:
WHERE a=1 OR b=2 → UNION ALL 或複合索引
- 定期維護:
ANALYZE TABLE 更新統計資訊、OPTIMIZE TABLE 整理碎片
總結
- InnoDB 叢集索引決定資料物理順序,**主鍵應單調遞增 (自增 ID/雪花 ID)**,避免頁分裂
- 二級索引葉子存主鍵值** → 覆蓋索引是避免回表的關鍵
- 複合索引遵循最左前綴** → 列序設計 = 業務查詢模式
- EXPLAIN 是放大鏡** → 讀懂 type/key/rows/Extra = 讀懂執行計劃
- 索引非越多越好** → 寫入代價、空間佔用、優化器負擔,定期審視
sys.schema_unused_indexes
- 上一篇文章: MySQL 運維開發工具箱大全:從監控到中間件的完整生態圖譜
- 下一篇文章: MySQL 版本升級完全指南:跨版本遷移策略、不兼容變更與實戰腳本
Copyright ©
程式碼之家 All Rights Reserved