optimizer_trace查不到结果是因为未在同一个会话中操作;开启、执行、查询三步必须在同一连接中完成,跨会话或断连会导致trace丢失,且需调大optimizer_trace_max_mem_size避免截断。

为什么 optimizer_trace 查不到结果?
执行完目标 SQL 后查 information_schema.optimizer_trace 却返回空或只有空 JSON,大概率是没在**同一个会话(session)**里操作。optimizer_trace 是会话级开关,开启、执行、查询三步必须在同一个连接中完成。跨会话、用不同客户端、或者中间断连重连都会导致 trace 丢失。
常见错误现象:SELECT * FROM information_schema.optimizer_trace 返回一行,但 TRACE 字段是空字符串或 {},MISSING_BYTES_BEYOND_MAX_MEM_SIZE 值为正数也说明内容被截断了——不是没记录,而是内存不够存全。
- 确认当前连接未变更:执行
SELECT CONNECTION_ID(),前后对比是否一致 - 不要用 GUI 工具自动重连(如某些 Navicat 配置),改用命令行 mysql 客户端更可控
- 若必须用 GUI,请确保“保持连接”且不启用“自动重连”选项
如何设置 optimizer_trace 才不丢关键信息?
默认的 optimizer_trace_max_mem_size=1048576(1MB)对简单查询够用,但多表 JOIN 或含子查询的语句极易触发截断,导致看不到 considered_execution_plans 或代价估算细节。这时 MISSING_BYTES_BEYOND_MAX_MEM_SIZE 字段会大于 0,就是明确警告。
实操建议:
- 分析前先设大一点:例如
SET SESSION optimizer_trace_max_mem_size = 4194304(4MB) - 加
end_markers_in_json=on,让 JSON 输出带阶段标记(如"join_optimization": { ... }),方便定位结构 - 避免全局开启:
SET GLOBAL optimizer_trace=...会影响所有新会话,生产环境严禁 - 不用
one_line=on:单行 JSON 几乎无法人工阅读,坚持one_line=off
从 trace JSON 里快速定位决策瓶颈
输出是嵌套 JSON,别从头硬读。重点关注三个顶层字段:
-
steps数组:按优化流程顺序排列,每项是一个阶段(如"join_preparation"、"join_optimization"、"condition_processing") -
considered_execution_plans:在join_optimization阶段下,列出所有被评估过的连接顺序和索引组合,含详细cost和rows估算 -
chosen_execution_plan:最终选定的计划,注意比对它和前面备选方案的cost差值——如果只差 0.01,说明优化器“随便选了一个”,往往意味着统计信息不准或索引区分度低
典型线索:
- 看到
"range_analysis_per_index": [...]里某个索引的index_dives_for_eq_ranges是false,说明优化器跳过了该索引的深度探测,可能因eq_range_index_dive_limit限制 -
"rows_estimation"中某张表预估行数是 1,实际是百万级,基本可断定ANALYZE TABLE没做或过期 - 多表 JOIN 时,
"table": "t2"出现在"best_covering_index_scan"下但没被选中,接着看到"cause": "cost",说明覆盖索引虽存在,但优化器算出来不如回表快——这时候得看key_len和ref是否真能利用上
optimizer_trace 和 EXPLAIN 的关系不是替代,而是补位
EXPLAIN 是“拍片结果”,optimizer_trace 是“诊断报告”。你不会只看 CT 片就开刀,也不会只读报告不看片子。真实调优中,必须交叉验证:
- EXPLAIN 显示
type=ALL(全表扫描),trace 里却看到优化器认真评估了多个索引——说明不是没索引,而是它算出来全扫更便宜,此时要查rows估算是否严重偏离 - EXPLAIN 显示用了
idx_a_b,但 trace 的considered_execution_plans里该索引的cost比全表还高,且"cause": "bad null filtering",说明字段有大量 NULL 导致选择性崩塌 - EXPLAIN 的
Extra出现Using temporary; Using filesort,trace 中对应阶段若显示"filesort_execution": {"rowcount": 123456, "examined_rows": 123456},说明排序确实发生在内存外,需调大sort_buffer_size或加覆盖索引
真正难啃的 case 往往藏在 trace 里那些看似合理的 cost 计算背后:比如 I/O 成本按 page 计,但 SSD 延迟远低于 HDD,而优化器仍按旧模型估算——这种底层假设偏差,只看 EXPLAIN 根本无从察觉。











