mysql如何选择执行计划的成本与代价评估

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

EXPLAIN 输出里的 cost 字段到底靠不靠谱

MySQL 8.0.19+ 的

EXPLAIN FORMAT=TREE
EXPLAIN FORMAT=JSON
会显示
cost
值,但它不是真实执行耗时,而是优化器基于统计信息估算的「I/O + CPU」相对代价。这个值只在同一条 SQL 的不同执行路径间有比较意义,跨语句、跨表、跨版本基本不可比。

cost
不含网络传输、锁等待、并发竞争等运行时开销
统计信息过期(
ANALYZE TABLE
没跑)会导致 cost 严重失真
小表全表扫描 cost 可能比大表走索引还低——因为优化器认为随机 I/O 比顺序扫更贵

真正影响执行计划选择的关键参数

优化器不是只看 cost,还会受以下硬性规则和阈值驱动:

eq_range_index_dive_limit
:当
IN
列表超过该值(默认 200),优化器跳过索引统计采样,直接按“全范围扫描”估算,容易误判走全表
range_optimizer_max_mem_size
:控制范围扫描估算内存上限,超限后退化为粗略估算,cost 偏离实际
索引基数(
Cardinality
)不准 →
rows
预估错误 → cost 计算崩盘
隐式类型转换(如
WHERE varchar_col = 123
)强制放弃索引,但
EXPLAIN
仍可能显示“Using index”,cost 却很低——这是假象

手动干预执行计划前必须验证的三件事

别急着加

FORCE INDEX
或改写 SQL,先确认底层是否真有问题:

SHOW INDEX FROM table_name
Cardinality
是否接近真实行数;偏差 >30% 就要
ANALYZE TABLE
执行
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE
,找
"best_covering_index"
"condition_filtering_pct"
,看优化器是否被过滤条件误导
对比
EXPLAIN ANALYZE
(MySQL 8.0.18+)的真实执行树,看哪一步的
actual_time
远超
estimated_cost
对应的预期
EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'shipped' AND created_at > '2024-01-01';

cost 估算失效的典型信号

当出现以下任一现象,说明 cost 已不可信,得靠观测而非估算做决策:

EXPLAIN
显示走了索引,但
profiling
performance_schema.events_statements_history
显示
Handler_read_next
高到离谱
相同 SQL 在从库上走索引,在主库上走全表(主从统计信息未同步)
rows
预估是 100,实际扫描 50 万行(
Handler_read_rnd_next
爆增)
加了
USE INDEX
后响应时间反而翻倍——说明优化器原本选的路径虽 cost 高,但实际更稳(比如避免临时表/文件排序)

优化器的 cost 是一张粗糙的地图,不是导航软件。它依赖统计信息的鲜度、配置参数的合理性、以及你没写的那些隐式假设。真正决定快慢的,永远是磁盘寻道次数、缓冲池命中率、和那条没被

EXPLAIN
显示出来的锁等待链。

相关推荐