mysql 5.7 的 optimizer_trace 默认关闭且仅保存当前会话最后一条语句的json追踪,易因16kb内存限制截断;需手动set启用、调大optimizer_trace_max_mem_size、严格会话内执行与查询,并聚焦trace中steps→join_optimization等关键路径分析cost与chosen决策。

MySQL 5.7 的 optimizer_trace 不是“开个开关就能直接看到完整决策链”,它默认只存最近一条语句的 JSON 追踪,且容易因内存限制被截断——必须手动调参、严格会话隔离、逐条验证。
如何确认并开启 optimizer_trace 功能
它默认是关闭的,不能靠配置文件一劳永逸。必须在当前会话中显式启用:
-
SET optimizer_trace = 'enabled=on';是最低要求,但建议加end_markers_in_json=on让 JSON 更易读 - 执行后用
SELECT * FROM information_schema.optimizer_trace\G查看结果,TRACE字段才是关键内容 - 注意:该视图只返回当前会话中**最后一条被追踪语句**的结果;前一条会被覆盖,不是历史记录表
- 如果查出来
TRACE是空字符串、MISSING_BYTES_BEYOND_MAX_MEM_SIZE> 0,说明 JSON 被截断了——这时要调大optimizer_trace_max_mem_size
为什么执行了 SQL 却查不到 TRACE 或内容为空
常见原因不是权限或语法错,而是会话与追踪逻辑不匹配:
- 必须在**同一个会话**里:先
SET optimizer_trace='enabled=on',再执行目标 SQL(比如SELECT、UPDATE),最后查information_schema.optimizer_trace -
EXPLAIN语句本身不会触发 trace;只有真实执行的 DML/SELECT 才会(EXPLAIN FORMAT=TRADITIONAL不算) - 如果 SQL 报错(如表不存在、列名错),优化器可能根本没走到完整优化阶段,
TRACE就为空或只有极简结构 -
INSUFFICIENT_PRIVILEGES = 1表示语句里引用了你没权限访问的视图或函数,TRACE字段强制清空
如何避免 JSON 截断和多语句覆盖问题
optimizer_trace_max_mem_size 默认仅 16KB,复杂查询的 trace 很容易超;而默认只保留 1 条,存储过程里多个子查询会互相覆盖:
- 增大内存上限:
SET optimizer_trace_max_mem_size = 1048576;(1MB,够大多数分析) - 查倒数第 N 条 trace:
SET optimizer_trace_offset = -2, optimizer_trace_limit = 1;再查视图,就能拿到上一条 - 想一次看连续多条(比如 CALL 存储过程里的 5 个子查询):
SET optimizer_trace_offset = -5, optimizer_trace_limit = 5; - 每次分析前加
SET optimizer_trace = 'enabled=off'; SET optimizer_trace = 'enabled=on';可清空旧 trace,避免干扰
从 TRACE JSON 里快速定位关键判断点
别通读几百行 JSON。重点关注这几层嵌套路径下的字段:
-
steps → join_optimization → considered_execution_plans:列出所有被评估过的执行计划,含 cost 估算值 -
steps → join_optimization → range_analysis → analyzing_range_alternatives:索引选择依据,比如为什么选ix_b而不是主键 -
steps → join_optimization → condition_processing:WHERE 条件是否被下推、重写(如IN转为OR) -
steps → join_execution → table下的using_join_cache、rows_examined_per_scan:实际扫描行数预估,对比EXPLAIN rows是否一致
真正难的是把 JSON 里 “cost=12.45” 和 “chosen=true” 对应到你改写的索引或 WHERE 条件上——这需要反复开关 trace、微调 SQL、比对 cost 变化,而不是指望一次输出就给出答案。











