cost字段不可靠,仅为优化器基于统计信息估算的相对I/O+CPU代价,仅同SQL不同路径间可比,跨语句/表/版本无效,且不含网络、锁等待等运行时开销。

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 显示出来的锁等待链。










