mysql 5.7 和 8.0 均支持 optimizer_trace,但 8.0 功能更完善:字段更全、结构更细、成本拆解更透明,且新增直方图、哈希连接、窗口函数等对应 trace 信息。

Optimizer Trace 在 MySQL 5.7 和 8.0 中是否可用
MySQL 5.7 支持 optimizer_trace,但功能受限;MySQL 8.0 不仅保留该功能,还大幅扩展了输出字段和结构,尤其在成本估算、索引选择依据、物化临时表决策等方面更透明。它不是“有无”的问题,而是“细不细、准不准”的问题。
开启方式与关键参数差异
两者都通过 SET optimizer_trace="enabled=on" 开启,但行为不同:
- MySQL 5.7 默认只记录单条语句的 trace,且
end_marker字段常为空,steps数组嵌套浅,缺失对cost_for_plan的逐项拆解 - MySQL 8.0 引入
optimizer_trace_max_mem_size(默认 1MB),并支持trace_limit和trace_offset分页查看多条 trace;更重要的是,message字段中会明确提示 “Using cost-based choice” 或 “Skipping index due to low selectivity”,而 5.7 多数时候只写 “considered” - 8.0 中
best_covering_index、best_covering_index_scan_cost等字段首次出现,可直接比对覆盖索引与回表的成本差值
常见误读:EXPLAIN FORMAT=JSON vs optimizer_trace
EXPLAIN FORMAT=JSON 是静态计划快照,不反映优化器实际试错过程;optimizer_trace 才是真正的“调试日志”。但要注意:
- 5.7 的 trace 中
range_analysis阶段常省略统计信息采样逻辑,比如不会告诉你 “Using histogram on col_a” —— 这个能力直到 8.0 引入直方图后才补全 - 8.0 的 trace 里会出现
"using_join_buffer": "flat"或"using_join_buffer": "hash",对应新版哈希连接策略;5.7 只有"using_join_buffer": "Block Nested Loop",且无 buffer 大小估算 - 若查询含窗口函数(如
RANK() OVER (PARTITION BY dept ORDER BY salary)),5.7 的 trace 直接报错或空输出;8.0 则会在steps中新增window_functions节点,并标注是否下推到存储引擎
容易被忽略的兼容性陷阱
升级后直接查 information_schema.OPTIMIZER_TRACE 表可能返回空,不是没开启,而是:
- MySQL 8.0 默认关闭
optimizer_trace的持久化存储(即不写入系统表),需显式SET optimizer_trace="enabled=on,one_line=off"并执行目标语句后,再查该表 - 5.7 的 trace 输出中
used_tables是字符串数组,8.0 改为对象数组,含database、table、alias字段 —— 若你用脚本解析 trace JSON,字段结构变更会导致解析失败 - 8.0 对子查询展开(subquery flattening)的 trace 标记更细,但若原 SQL 含
SQL_NO_CACHE或STRAIGHT_JOIN,部分 trace 步骤会被跳过,这点在 5.7 中不明显
真正难调的从来不是 trace 是否显示,而是看到 “cost=124.67” 却不知道这个数字里有多少来自 index_statistics、多少来自 histogram、又有多少是硬编码的启发式惩罚值 —— MySQL 8.0 至少把这部分拆开了,5.7 没有。











