索引是查詢性能的核心杠桿。本文系統總結索引創建原則、失效場景、EXPLAIN 實戰分析,並給出慢查詢優化標準化步驟,附大量實測案例。
(a,b,c,d),查詢 a=1 AND b=2 AND c>3 AND d=4 僅用到 (a,b,c),d 失效;調整順序為 (a,b,d,c) 可全部命中COUNT(DISTINCT col)/COUNT(*),唯一鍵=1,性別類字段接近 0。Join 字段建議 > 0.1(平均 10 行掃描 1 行)FROM_UNIXTIME(create_time) = '2014-05-29'create_time = UNIX_TIMESTAMP('2014-05-29')(a) 需 (a,b) 時,直接 ALTER TABLE ... ADD INDEX (a,b) 覆蓋舊索引| 場景 | 原因 | 對策 |
|---|---|---|
LIKE '%abc' 以%開頭 | B+Tree 無法利用前綴匹配 | 全文索引 / 反向存儲 / 應用層處理 |
| 隱式類型轉換 | WHERE varchar_col = 123(無引號) | 字符串常量必須加引號 |
| 不滿足最左列 | 聯合索引 (a,b) 查 WHERE b=1 | 調整索引順序或建單列索引 |
| OR 條件列索引不全 | WHERE a=1 OR b=2,b 無索引 | 改用 UNION ALL 或為 b 建索引 |
| 索引列參與運算 | WHERE id+1 = 10 | 移項改寫 WHERE id = 9 |
以 rental 表聯合索引 idx_rental_date(rental_date, inventory_id, customer_id) 為例:
EXPLAIN SELECT * FROM rental
WHERE rental_date='2005-05-25' AND inventory_id=373 AND customer_id=343;
-- type=ref, key=idx_rental_date, rows=1 ✓
ALTER TABLE rental ADD UNIQUE INDEX idx_rental_date(...);
-- 同條件下 type=const, rows=1 ✓
EXPLAIN SELECT * FROM rental WHERE customer_id >= 373 AND customer_id <= 400;
-- type=range, key=idx_fk_customer_id, rows=745
EXPLAIN SELECT last_update FROM payment
WHERE payment_date='2006-02-14' AND amount=3.98;
-- Extra=Using index,無需回表 ✓
CREATE INDEX idx_title_desc_part ON film_text(title(10), description(20));
EXPLAIN SELECT title FROM film_text WHERE title LIKE 'AFRICAN%';
-- key=idx_title_desc_part, type=range ✓
SET SESSION query_cache_type=OFF; SELECT SQL_NO_CACHE ... 確認真慢type、key、rows、Extra 是否符合預期SHOW STATUS LIKE 'Handler_read%';
-- Handler_read_key 高 = 索引命中好
-- Handler_read_rnd_next 高 = 大量全表掃描,索引失效或 SQL 問題