MySQL 查詢優化器對 WHERE 條件有一套自動改寫與裁剪規則。理解這些規則,能幫你寫出更易優化的 SQL,也能看懂 EXPLAIN 的執行計畫。
((a AND b) AND c OR (((a AND b) AND (c AND d))))
-- 簡化為
(a AND b AND c) OR (a AND b AND c AND d)
(a < b AND b = c) AND a = 5
-- 推導為
b > 5 AND b = c AND a = 5
(B >= 5 AND B = 5) OR (B = 6 AND 5 = 5) OR (B = 7 AND 5 = 6)
-- 簡化為
B = 5 OR B = 6
WHERE id > 100 + 200 → 優化器直接當成 id > 300。
COUNT(*) 無 WHERE 直接從表元資料讀取(MyISAM)或掃描最小索引(InnoDB)。NOT NULL 欄位同理可快速統計。WHERE 1=0 直接返回空結果,不掃表。HAVING 無 GROUP BY 時自動合併為 WHERE。優化器識別「常數表」(空表、單行表、唯一索引等值查詢),優先讀取並將其值視為常數代入後續聯結,大幅縮小搜尋空間。
-- 範例:t1 主鍵=1 為常數表
SELECT * FROM t1, t2 WHERE t1.pk = 1 AND t2.fk = t1.id;
ORDER BY/GROUP BY 欄位來自同一表 → 該表優先驅動。SQL_SMALL_RESULT → 強制用記憶體臨時表而非排序。DISTINCT + ORDER BY 常觸發臨時表。SELECT 只涉及索引欄位 → 只讀索引樹,不回表。| 模式 | SQL 範例 | 優化點 |
|---|---|---|
| 單值聚合 | SELECT COUNT(*) FROM tbl | 直接讀元資料 |
| 索引區間極值 | SELECT MIN(k1),MAX(k1) FROM tbl | 只走索引樹左右最深節點 |
| 前綴等值+極值 | SELECT MAX(k2) FROM tbl WHERE k1=const | 索引 (k1,k2) 直接定位 |
| 排序+限制 | SELECT * FROM tbl ORDER BY k1,k2 LIMIT 10 | 索引順序掃描停早 |
| 覆蓋索引查詢 | SELECT k1,k2 FROM tbl WHERE k1=val | 不回表,極快 |
| 索引分組 | SELECT k2 FROM tbl GROUP BY k1 | 索引順序天然分組 |
ORDER BY key_part1, key_part2 若符合索引順序(或倒序 DESC),可省略 filesort,直接按索引輸出。