MySQL 查詢優化器(Query Optimizer)單一核心目標:**以最小代價找到符合條件的行**。核心策略:盡可能使用索引,並選擇最嚴格(選擇性最高)的索引,儘早過濾掉不符合條件的行。
-- 優化器識別 WHERE 0 永假,直接返回空結果,不掃描表
EXPLAIN SELECT * FROM tbl_name WHERE 0\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Impossible WHERE
假設查詢:
SELECT col3 FROM mytable
WHERE col1 = 'value1' AND col2 = 'value2';
-- col1、col2 均有索引
優化器估算:
col1 = 'value1' 匹配 900 行(選擇性 900/總行數)col2 = 'value2' 匹配 300 行(選擇性較高)決策:優先用 col2 索引讀取 300 行,再回表過濾 col1,僅 270 次失敗;若先用 col1 則 870 次失敗。優化器選擇代價更小的 col2 索引。
INT vs BIGINT、CHAR(10) vs VARCHAR(10) 視為相容,但 CHAR(10) vs CHAR(12) 會阻礙索引使用
-- 惡例:隱式轉換導致索引失效
WHERE varchar_col = 123; -- 數值與字串比較
-- 良例:統一類型
WHERE varchar_col = '123';
ANALYZE TABLE tbl_name; 更新索引基數,幫助優化器準確估算 rowstype(目標 ref/eq_ref/range)、key(實際用索引)、rows(預估掃描行)、Extra(Using index/where/temporary/filesort)FORCE INDEX (idx_name)、IGNORE INDEX (idx_name)、USE INDEX (idx_name)(謹慎使用,優化器通常更聰明)| 欄位 | 含義 | 優秀值 | 警示值 |
|---|---|---|---|
| id | 查詢序號 | - | - |
| select_type | 查詢類型 | SIMPLE | DEPENDENT SUBQUERY, UNCACHEABLE SUBQUERY |
| table | 訪問的表 | - | <derivedN>, <subqueryN> |
| partitions | 匹配分區 | 具體分區名 | ALL (全分區掃描) |
| type | 訪問類型(關鍵) | system > const > eq_ref > ref > range > index > ALL | ALL (全表掃描) |
| possible_keys | 理論可用索引 | - | NULL (無索引可用) |
| key | 實際使用索引 | 具體索引名 | NULL (未用索引) |
| key_len | 使用索引長度 | 盡可能長(複合索引前綴) | 過短(未用完整複合索引) |
| ref | 關聯比較依據 | const, func, col_name | - |
| rows | 預估掃描行數 | 接近實際返回行數 | 遠大於返回行數 |
| filtered | 條件過濾比例 | 100% | < 10% |
| Extra | 額外資訊 | Using index, Using where | Using temporary, Using filesort, Using join buffer |
IN 列表過長(> range_optimizer_max_mem_size)會退化為全表掃描ANALYZE TABLE ... UPDATE HISTOGRAM 解決非均勻分布估算偏差