optimizer_trace 能观察谓词消除过程,而 explain 不能;它通过 json 中的 "condition_processing" 等字段记录条件化简、谓词下推等优化步骤。

EXPLAIN 只能看到结果,看不到谓词消除过程
想确认优化器是否做了谓词化简(比如 WHERE age > 25 AND age > 20 → WHERE age > 25),单靠 EXPLAIN 是不行的。它只展示最终执行计划,不暴露中间逻辑变换步骤。
真正能观察谓词消除的,是 OPTIMIZER_TRACE —— 它会记录优化器从语法树到逻辑重写、再到物理计划的每一步决策,包括“条件化简”“谓词下推”“等价重写”等子阶段。
开启 OPTIMIZER_TRACE 并捕获谓词化简日志
执行前需启用追踪,并限制只看当前语句(避免干扰):
SET optimizer_trace="enabled=on,one_line=off"; SET optimizer_trace_max_mem_size=1048576; SELECT * FROM users WHERE age > 25 AND age > 20 ORDER BY id LIMIT 10;
然后查追踪结果:
SELECT trace FROM information_schema.OPTIMIZER_TRACE;
在返回的 JSON 中重点找这几个字段:
-
"condition_processing":明确列出原始条件、化简后条件、以及操作类型(如"condition": "simplified") -
"transformations_to_nested_joins"或"substitute_generated_columns":若涉及子查询或生成列,这里会体现谓词下推时机 -
"rows_estimation"下的"table": "users"节点里,"range_analysis"会显示优化器实际使用的过滤条件(即已消除冗余后的谓词)
常见谓词消除场景与对应 trace 片段特征
不是所有谓词都会被消除,触发条件取决于表达式结构和统计信息。典型可消除组合:
-
WHERE a = 1 AND a = 1→ 合并为单个等值条件;trace 中"condition_processing"的"resulting_condition"字段会变短 -
WHERE a > 10 AND a > 5→ 简化为a > 10;注意看"original_condition"和"simplified_condition"的对比 -
WHERE NOT (a = b)→ 改写为a b;这属于等价谓词重写,在"transformation"字段中标为"negation_elimination"或"comparison_rewriting" -
WHERE a IN (1,2) OR a = 1→ 去重合并;trace 中"in_to_exists"或"or_simplification"可能出现
但像 WHERE a > 10 OR a 这类无法合并的范围,优化器通常不做化简,而是直接交给存储引擎处理 —— 此时 trace 里 <code>"condition_processing" 可能为空或仅标记为 "none"。
容易忽略的关键点:统计信息影响谓词是否被下推
谓词能不能被下推到存储引擎层(比如 InnoDB),不只看语法,还依赖列的基数估算。如果 ANALYZE TABLE users 没更新过,优化器可能误判选择性,导致本该下推的谓词留在执行器层做二次过滤。
这时你在 OPTIMIZER_TRACE 的 "range_analysis" 里会看到:
-
"analyzing_range_alternatives"下多个索引尝试,但最终选了全表扫描 -
"using_filesort"或"using_temporary"出现,说明谓词没被有效利用 -
"rows"估值远高于实际,提示统计不准 —— 这时候ANALYZE TABLE比调参更管用
谓词消除本身很快,但它的下游影响(比如是否走索引、是否触发 filesort)才是真正拖慢查询的地方。别只盯着“有没有简化”,要看“简化之后,执行路径变好了没有”。











