索引是查詢性能的關鍵,但「索引越多越好」是嚴重誤區。本文總結 9 大核心判斷依據,幫助你構建高效、精準的索引體系。
主鍵自動建立聚簇索引;外鍵列必須手動建立索引 (InnoDB 不自動創建),否則修改父表時會鎖定子表全表掃描,導致嚴重阻塞。
小表 (幾百行) 全表掃描極快,索引維護開銷反而大於收益。大表無索引查詢將災難性。
`ON a.id = b.a_id` 中 `a.id` (通常是 PK) 和 `b.a_id` 都需索引。被驅動表的關聯列無索引會導致 Nested Loop Join 退化為全表掃描。
`WHERE status=1 AND create_time>'2023-01-01'` 中 `status`、`create_time` 為高頻過濾列,應建索引。
選擇性 = `COUNT(DISTINCT col) / COUNT(*)`。越接近 1 越好 (如身份證號、手機號)。性別、狀態枚舉 (區分度極低) **不適合**建單列索引。
聯合索引 `(a, b, c)` 等價於擁有 `(a)`、`(a,b)`、`(a,b,c)` 三個索引。
決策樹:
每個索引都增加寫入開銷 (B+樹維護、Undo Log、Redo Log)。頻繁寫入表索引數建議 **≤ 3-5 個**,優先保障核心查詢。
| 場景 | 推薦索引類型 | 語法示例 |
|---|---|---|
| 主鍵、唯一約束 | PRIMARY KEY / UNIQUE | `PRIMARY KEY (id)`, `UNIQUE KEY uk_phone (phone)` |
| 單列高頻過濾、高區分度 | 普通索引 | `INDEX idx_create_time (create_time)` |
| 多列固定組合查詢 (AND) | 聯合索引 | `INDEX idx_status_time (status, create_time)` |
| 模糊查詢 `LIKE 'prefix%'` | 普通/聯合索引 (最左匹配) | `INDEX idx_name (name)` → `WHERE name LIKE 'abc%'` |
| 全文搜索 `MATCH...AGAINST` | 全文索引 | `FULLTEXT idx_content (content)` (MySQL 5.6+ InnoDB 支持) |
| JSON 字段查詢 | 虛擬列 + 索引 / 多值索引 (8.0) | `ALTER TABLE t ADD COLUMN v INT GENERATED ALWAYS AS (json_extract(data, '$.id')), ADD INDEX idx_v (v)` |
EXPLAIN SELECT * FROM orders WHERE user_id=100 AND status=1;
-- 關鍵看:type=ref/range, key=idx_user_status, rows=預估掃描行數 (應極小), Extra=Using index condition
索引設計本質是**空間換時間、寫入換讀取**的權衡。**依據業務查詢模式建索引,而非依據表結構**。遵循「高區分度、最左前綴、少而精、定期清理」十六字真言,拒絕過度索引與無效索引。