condition_processing 是关键入口,记录 where/having/on 条件从原始写法经等价改写(如常量传播、隐式转换)到最终评估形式的全过程,揭示索引失效等根因。

Optimizer Trace 能直接看到 MySQL 优化器对 SQL 做了哪些等价改写,比如常量传播、条件归并、隐式类型转换触发的索引失效——但前提是得进到 condition_processing 步骤里翻,不是查完 information_schema.optimizer_trace 就自动明白。
为什么 condition_processing 是关键入口
优化器所有“悄悄改你 SQL”的动作都集中在这里:condition_processing 记录了 WHERE/HAVING/ON 条件从原始写法 → 经过一系列 transformation → 最终被评估的形式。它不只告诉你“用了什么索引”,而是解释“为什么用这个而不是那个”。
- 常见错误现象:EXPLAIN 显示
key为空,但字段明明有索引;TRACE 里original_condition和resulting_condition对不上,说明条件被重写了 - 使用场景:当
WHERE a = 123 AND b = 'abc'没走联合索引,就去condition_processing看是否因隐式转换(比如a是字符串字段却传了数字)导致整个条件失效 - 参数差异:
transformation字段值如equality_propagation、constant_propagation、trivial_condition_removal都代表一类改写行为,不是所有版本都输出全部;MySQL 8.0+ 比 5.7 更完整
如何定位 condition_processing 的具体位置
steps 数组里找第二项(通常是 join_optimization),再进它的 steps 数组,第一个子项大概率就是 condition_processing。别在顶层或 rows_estimation 里瞎找。
- 执行顺序必须严格:先
SET optimizer_trace = "enabled=on", end_markers_in_json = on,再执行目标SELECT,最后查information_schema.optimizer_trace;EXPLAIN不触发 trace - 如果
TRACE字段是空字符串,先检查INSUFFICIENT_PRIVILEGES = 1或MISSING_BYTES_BEYOND_MAX_MEM_SIZE > 0;前者说明语句里引用了无权限对象,后者说明 JSON 被截断,需调大optimizer_trace_max_mem_size - 容易踩的坑:在 autocommit=1 下执行 SELECT 后立刻提交,trace 内容会被清空;务必加
SET autocommit = 0,查完再ROLLBACK
看懂 resulting_condition 里的真实意图
resulting_condition 不是美化后的 SQL,而是优化器内部使用的逻辑表达式。它可能暴露你没意识到的问题:
- 出现
multiple equal('IND', `city`.`CountryCode`):说明做了等值传播,通常没问题 - 出现
`t`.`id` + 0 = 123:说明字段id是字符串类型,而你传了数字,触发隐式转换,索引失效 - 出现
cast(`t`.`created_at` as date) = '2025-01-01':函数包裹导致无法走索引,哪怕created_at有索引 - 如果
resulting_condition变成true或false,说明条件被全量折叠(比如WHERE 1=1),但也要警惕是否因统计信息异常导致误判
真正难的是把 resulting_condition 和后续 ref_optimizer_key_uses、analyzing_range_alternatives 连起来看——改写后的条件是否还匹配索引定义,是否仍满足 range 访问前提,这些环环相扣,漏掉一步就找不到根因。











