MySQL 使用 B-tree 索引,單次查詢磁碟搜尋次數估算公式:
log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1
index_block_length:通常 1024 bytesdata_pointer_length:通常 4 bytesMEDIUMINT 索引 (3 bytes) → 約 4 次搜尋寫入成本:約 4 次搜尋定位新索引位置,更新約 2 次搜尋。
key_buffer_size只要索引能放入快取 (OS 或 MySQL key_buffer_size),效能僅隨資料量對數增長。資料超出快取才急劇下降。對策:隨資料增長同步調大 key_buffer_size (MyISAM)。
EXPLAIN SELECT ... 確認 type、key、rowsANALYZE TABLE tbl 或 myisamchk --analyze,更新 Cardinality (不重複值估算),優化器據此選擇連接順序myisamchk --sort-index --sort-records=1 (按索引 1 排序),適合按主鍵順序大量讀取,首次執行耗時極長MySQL 優化器在執行前自動進行以下轉換 (持續改進中,文檔未盡列舉):
| 優化規則 | 轉換前 | 轉換後 |
|---|---|---|
| 移除多餘括號 | ((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 |
| 常數表達式單次計算 | 查詢中重複常數運算 | 只計算一次 |
COUNT(*) 無 WHERE (MyISAM/MEMORY) | SELECT COUNT(*) FROM t | 直接從表元資料讀取,極快 |
| 早期偵測不可能條件 | SELECT * FROM t WHERE 1=0 | 直接回傳空結果,不掃描 |
HAVING 合併為 WHERE | 無 GROUP BY 時 | 等價轉換 |
| 連接條件下推 | 多表連接 | 為每表構造最簡 WHERE,盡早過濾 |
| 常數表優先讀取 | 空表、單行表、PK/UK 查詢 | 優先處理,作為連接基準 |
PRIMARY KEY 或 UNIQUE NOT NULL 索引所有部分做等值比較ORDER BY/GROUP BY 欄位來自同一表,該表優先連接ORDER BY 與 GROUP BY 不一致或涉及非第一表欄位 → 建立臨時表SQL_SMALL_RESULT 強制使用記憶體臨時表傳統限制:每表最多用一個索引。Index Merge 允許合併多個 ref/ref_or_null/range 掃描結果:
SELECT * FROM t WHERE key1 = 10 OR key2 = 20;
-- 可同時使用 key1 和 key2 索引,結果合併
EXPLAIN 顯示 type=index_merge, key=key1,key2
適用條件:OR 條件分別能用不同索引,且為 ref/range 類型。
col IS NULL 等同 col = constant 優化,可用索引/範圍查詢<=> (NULL-safe 等值) 同樣優化WHERE key=1 OR key=2 OR key IS NULL → 索引合併NOT NULL 欄位的 IS NULL → 優化器直接判定為 FALSE (除非來自 LEFT JOIN 右表)col = expr AND col IS NULL 額外優化 (常見於子查詢),EXPLAIN 顯示 ref_or_nullIS NULLORDER BY 觸發臨時表LIMIT n 配合 DISTINCT:找到 n 筆不同值即停止EXPLAIN 決定)A LEFT JOIN B ON cond 執行規則:
LEFT JOIN ... WHERE b.col IS NULL 且 b.col NOT NULL → 找到第一匹配即停止-- 慢:b 在 a 之前讀取,但 LEFT JOIN 強制 a 先於 d 讀取,導致 b 全表掃描
SELECT * FROM a, b LEFT JOIN c ON c.key=a.key LEFT JOIN d ON d.key=a.key
WHERE b.key = d.key;
-- 快:調整表順序,b 移至最前
SELECT * FROM b, a LEFT JOIN c ON c.key=a.key LEFT JOIN d ON d.key=a.key
WHERE b.key = d.key;
-- 或使用 STRAIGHT_JOIN 強制順序
若 WHERE 條件對產生的 NULL 行恆為 FALSE (如 t2.col=5 且 col NOT NULL),LEFT JOIN 自動轉為內連接,優化器可自由調整順序。
Cardinality、直方圖 (8.0+)、索引選擇性LIMIT 早期終止理解優化器邏輯,善用 EXPLAIN、ANALYZE TABLE、OPTIMIZE TABLE、合理索引設計,是查詢調校的核心技能。