MySQL 優化器並非全知全能,當 ORDER BY 干擾索引選擇導致掃描行數從 757 暴增至 22 萬時,USE INDEX 成為精準干預的手術刀。本文通過真實線上案例,演示「EXPLAIN 發現誤判 → USE INDEX 強制修正 → 效能驗證」的完整優化閉環。
CREATE TABLE arena_match_index (
tid INT UNSIGNED NOT NULL DEFAULT 0,
mid INT UNSIGNED NOT NULL DEFAULT 0,
`group` INT UNSIGNED NOT NULL DEFAULT 0,
round TINYINT UNSIGNED NOT NULL DEFAULT 0,
day DATE NOT NULL DEFAULT '0000-00-00',
begintime DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
UNIQUE KEY tm (tid, mid),
KEY mid (mid),
KEY begintime (begintime),
KEY dg (day, `group`), -- 聯合索引:天 + 組
KEY td (tid, day)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
SELECT round FROM arena_match_index
WHERE day='2010-12-31' AND `group`=18 AND begintime<'2010-12-31 12:14:28'
ORDER BY begintime LIMIT 1;
EXPLAIN ...
type: range, key: begintime, rows: 226480, Extra: Using where
原因:ORDER BY begintime 讓優化器誤以為走 begintime 索引可避免 filesort,實際上 WHERE 條件中 day 和 group 是高選擇性等值條件,應優先走 dg 聯合索引。
EXPLAIN SELECT round FROM arena_match_index USE INDEX (dg)
WHERE day='2010-12-31' AND `group`=18 AND begintime<'2010-12-31 12:14:28'
ORDER BY begintime LIMIT 1;
type: ref, key: dg, key_len: 7, rows: 757, Extra: Using where; Using filesort
效能提升:掃描行數減少 99.7%,耗時從 30 秒降至毫秒級(百倍+提升)。
EXPLAIN SELECT round FROM arena_match_index
WHERE day='2010-12-31' AND `group`=18 AND begintime<'2010-12-31 12:14:28' LIMIT 1;
type: ref, key: dg, rows: 717, Extra: Using where
證明:ORDER BY 是干擾優化器決策的關鍵因素。
| 語法 | 語義 | 適用場景 |
|---|---|---|
USE INDEX (idx_list) | 建議優化器優先考慮列表中的索引,仍可選擇全表掃描 | 優化器誤判、需輕微引導 |
FORCE INDEX (idx_list) | 強制使用列表索引,除非無法使用才退回全表掃描 | 確信某索引最優、需硬性約束 |
IGNORE INDEX (idx_list) | 禁止優化器使用列表索引 | 某索引導致災難性計劃、需屏蔽 |
SELECT * FROM information_schema.OPTIMIZER_TRACE 或審計日誌發現。優化器是智能助手,Hint 是緊急制動器。懂得何時踩剎車、何時信任助手,是 SQL 調優從入門到精通的分水嶺。