开启optimizer_trace后无法查看完整决策链,因其默认仅保存当前会话最后一条语句的json快照且易因16kb内存限制被截断;需手动调大optimizer_trace_max_mem_size、严格同会话执行、启用end_markers_in_json=on并逐条验证。

直接开 optimizer_trace 不等于能看到完整决策链——它默认只存当前会话最后一条语句的 JSON 快照,且极易因 16KB 内存限制被截断。必须手动调参、严格会话内执行、逐条验证才能拿到有效信息。
为什么开了 optimizer_trace 却查不到 TRACE 或内容为空
这不是权限或语法问题,而是追踪逻辑没对上:
- 必须在同一个会话里:先
SET optimizer_trace = 'enabled=on', end_markers_in_json=on,再执行真实SELECT/UPDATE(EXPLAIN不触发 trace) - 语句报错(如表不存在、列名错)会导致优化器跳过完整优化阶段,
TRACE字段为空或只有极简结构 -
INSUFFICIENT_PRIVILEGES = 1表示你对语句中涉及的表/视图没有SELECT权限,trace 强制清空 - 如果
autocommit = 1,SELECT执行完立刻提交,trace 内容可能被清掉;建议先SET autocommit = 0,查完再ROLLBACK
如何避免 JSON 截断和多语句覆盖
optimizer_trace_max_mem_size 默认仅 1048576 字节(1MB),复杂 JOIN 或含子查询的语句很容易触发 MISSING_BYTES_BEYOND_MAX_MEM_SIZE > 0,关键路径被砍掉:
- 立即调大内存:执行
SET optimizer_trace_max_mem_size = 4194304(4MB) - 查上一条 trace:用
SET optimizer_trace_offset = -2, optimizer_trace_limit = 1,再查information_schema.optimizer_trace - 查连续多条(比如存储过程里 5 个子查询):
SET optimizer_trace_offset = -5, optimizer_trace_limit = 5 - 每次分析前加
SET optimizer_trace = 'enabled=off'; SET optimizer_trace = 'enabled=on';,清掉旧记录防干扰
怎么看 TRACE 里真正有用的决策信息
别只盯着顶层字段,重点翻 steps 数组里的嵌套结构:
-
join_optimization → condition_processing:看 WHERE 条件是否被重写(比如隐式类型转换导致索引失效) -
join_optimization → range_analysis → analyzing_range_alternatives:如果看到"index": "PRIMARY"但"rows": 999999,说明优化器认为全表扫比走主键范围更快——大概率缺复合索引 -
join_optimization → considered_execution_plans:列出所有候选计划及其cost,对比“被选中”和“被放弃”的 cost 差值 -
ref_optimizer_key_uses块里若"using_index": false,得回溯前面condition_processing是否把条件化简丢了
最常被忽略的是 end_markers_in_json=on ——不加这个,JSON 里所有 } 都没注释标记,嵌套深了根本找不到哪段对应 join_preparation 还是 join_optimization。别省这一个参数。











