MySQL基于成本模型选择最优执行计划,EXPLAIN是判断依据:type反映访问效率,key与possible_keys不一致说明索引被弃用,rows为预估扫描行数,Extra中Using filesort或temporary提示排序/分组未走索引;索引未被选用主因是优化器估算其成本更高,如数据倾斜、统计信息过期、联合索引顺序错误、隐式类型转换等;EXPLAIN ANALYZE可验证实际执行情况,对比预估与实际行数及耗时,定位回表开销大或临时表等问题。

MySQL 选择最优执行计划,不是靠“猜”,而是基于成本模型(Cost-Based Optimizer, CBO)对多个候选路径做量化评估后选成本最低的那个——cost 越低,越可能被选中。
看懂 EXPLAIN 是判断“是否最优”的唯一入口
不查 EXPLAIN,就等于闭眼调优。它暴露了优化器的全部决策依据:
-
type字段直接反映访问效率:从const→eq_ref→ref→range→index→ALL,性能逐级下降;出现ALL基本意味着没走索引或索引失效 -
key和possible_keys不一致?说明优化器放弃了你建的索引——常见原因包括:索引列参与了函数/表达式、隐式类型转换、WHERE条件未覆盖最左前缀 -
rows是预估扫描行数,不是实际值;但若远大于结果集(比如查 1 行却扫 10 万行),大概率存在索引未命中或统计信息过期 -
Extra中的Using filesort或Using temporary是强信号:ORDER BY / GROUP BY 没走索引,正在用磁盘临时文件排序或建临时表
为什么明明有索引,优化器却不选?
索引存在 ≠ 索引可用。优化器弃用索引的核心原因是:它算出来用这个索引的成本反而更高。
- 数据分布倾斜:比如某字段 95% 值为
'active',即使加了索引,优化器也会认为全表扫描更便宜(因为要回表读取大量数据) - 统计信息陈旧:
ANALYZE TABLE没跑过,优化器基于错误基数估算成本;尤其在大批量 INSERT/DELETE 后必须手动刷新 - 联合索引顺序错位:
KEY idx_name_age (name, age)支持WHERE name = ?或WHERE name = ? AND age > ?,但不支持WHERE age = ? -
隐式转换强制放弃索引:
WHERE phone = 13800138000(phone 是VARCHAR)会触发字符串→数字转换,导致索引失效
EXPLAIN ANALYZE 才是真·照妖镜
EXPLAIN 只显示预估,而 EXPLAIN ANALYZE(MySQL 8.0+)会真实执行并返回各阶段耗时、实际扫描行数、是否真正用了索引等硬指标。
EXPLAIN ANALYZE SELECT * FROM employees WHERE name = '张三' AND age > 25;
- 对比
rows(预估)和actual rows(实际):若相差 10 倍以上,说明统计不准或查询条件选择性误判 - 观察
actual time分布:如果 “Index lookup” 很快但 “Read data” 占比极高,说明回表开销大,考虑改成覆盖索引 - 注意 “Materialize” 或 “Create temporary table” 出现场景:这类操作无法通过加索引消除,需重构 SQL 或调整
tmp_table_size等参数
真正卡住性能的,往往不是“有没有索引”,而是“优化器信不信这个索引值得用”。别只盯着 CREATE INDEX,多跑 EXPLAIN ANALYZE,再结合 SHOW INDEX 和 INFORMATION_SCHEMA.STATISTICS 看基数,才能看清成本模型背后的真实逻辑。










