mysql执行计划是如何生成的_SQL执行策略解析

来源:这里教程网 时间:2026-02-28 20:48:39 作者:

MySQL优化器如何选择执行计划

MySQL不按SQL字面顺序执行,而是由优化器生成成本最低的执行计划。这个过程不是确定性的——同一SQL在不同数据分布、索引状态或统计信息下,可能生成完全不同的执行计划。

优化器基于

cost_model
估算每个候选计划的I/O和CPU开销,核心输入包括:表行数(
INFORMATION_SCHEMA.TABLES.TABLE_ROWS
)、索引基数(
SHOW INDEX FROM tbl
)、列值分布直方图(MySQL 8.0+)、以及是否启用
optimizer_switch
中的各项规则(如
index_merge=on
)。

统计信息过期会导致误判:执行
ANALYZE TABLE t
强制刷新,而非依赖自动采样
FORCE INDEX
能绕过优化器选择,但仅解决表层问题;真正要查的是为什么优化器认为全表扫描更“便宜”
隐式类型转换(如
WHERE varchar_col = 123
)会让索引失效,且优化器仍可能选错路径,因为类型转换发生在执行阶段,优化器无法准确预估过滤效果

EXPLAIN输出里哪些字段最关键

EXPLAIN
不是执行日志,而是优化器“打算怎么做”的快照。重点关注
type
key
rows
Extra
四列,它们直接暴露策略缺陷:

type
ALL
index
:大概率缺失有效索引,或查询条件未覆盖索引最左前缀
key
NULL
:优化器明确放弃使用索引,常见于
OR
条件未被索引覆盖、函数包裹字段(如
WHERE YEAR(create_time) = 2023
rows
远大于实际结果集:说明索引选择不当或统计不准,
rows
是优化器预估的扫描行数,不是返回行数
Extra
Using filesort
Using temporary
:排序或分组未走索引,需检查
ORDER BY
/
GROUP BY
字段是否在索引中连续出现

为什么FORCE INDEX有时反而更慢

强制指定索引会跳过成本估算,但不改变底层执行逻辑。如果强制的索引无法覆盖查询所需字段(即非覆盖索引),MySQL仍需回表读取完整行,而优化器原本选的全表扫描可能因顺序I/O更快。

复合索引
(a,b,c)
上执行
SELECT * FROM t WHERE a=1 ORDER BY b
,即使
FORCE INDEX(a,b)
c
字段仍需回表;若表不大,全表扫描+内存排序反而更优
FORCE INDEX
不阻止
Using filesort
:它只影响访问路径,不影响排序方式
EXPLAIN FORMAT=JSON
查看
used_key_parts
used_columns
,确认索引是否真正被“用满”

统计信息不准时怎么快速验证

优化器严重依赖统计信息,但

ANALYZE TABLE
默认采样率低(
innodb_stats_persistent_sample_pages=20
),大表容易误判。

临时提高采样精度:
SET SESSION innodb_stats_persistent_sample_pages = 100
,再执行
ANALYZE TABLE t
检查实际基数是否失真:
SELECT COUNT(DISTINCT col) FROM t
vs
SHOW INDEX FROM t
里的
Cardinality
值,偏差超5倍就该怀疑
禁用持久化统计(
innodb_stats_persistent=OFF
)可让每次重启后重新采样,适合测试环境快速验证,但生产慎用

执行计划不是配置出来的,是数据、索引、统计信息和查询结构共同作用的结果。改SQL、加索引、刷统计,三者常需同步调整,单点改动往往无效。

相关推荐