执行计划中的“隐藏信息”:读懂optimizer trace,看透优化器的每一步决策

简介: 小耶分享MySQL优化干货:EXPLAIN只告诉你“选了什么”,而Optimizer Trace才是揭秘优化器“为什么这么选”的关键工具!它像行车记录仪,完整追踪成本估算、索引选择、规则应用全过程。四步启用,精准定位全表扫描等异常根因,助你从执行计划阅读者进阶为优化器理解者。

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

前面我们讲了Extra列里的8个性能信号——Using temporaryUsing filesortUsing index condition……把这些“黑话”都拆了一遍。但还有一个更深的问题没解决:

如果执行计划看起来不合理,怎么知道优化器“为什么”会这么选?

EXPLAIN能告诉你“选了哪个计划”,但说不出“为什么选它”。你看到type=ALL,知道全表扫描了,但不知道为什么——明明有索引,优化器为什么不走?

这时候就需要​Optimizer Trace​。

在MySQL 5.6之前,优化器就像一个黑盒子——你只能看到最终结果,看不到决策过程。Optimizer Trace就是打开这个黑盒子的钥匙。它可以跟踪优化器做出的​每一步决策​——访问方式的选择、成本估算、各种转换规则的应用,全部记录下来。从MySQL 5.6开始,设计MySQL的大叔贴心地提供了这个功能,让我们可以方便地查看优化器生成执行计划的整个过程。

一、Optimizer Trace是什么?——优化器的“行车记录仪”

打个比方,EXPLAIN是一张“行车路线图”——告诉你最后走了哪条路。而Optimizer Trace是“行车记录仪”——它录下了司机在路上做的每一个决策:为什么没走高速、为什么在这个路口右转、为什么绕了一段路。

Optimizer Trace记录的正是优化器从接收SQL到最终选定执行计划的完整过程,包括:

  • 生成了哪些候选执行计划
  • 每个计划的成本估算
  • 应用了哪些优化规则
  • 最终选择了哪个计划,以及为什么

有了这些信息,你不仅能知道优化器“选了什么”,还能知道它“为什么这么选”。

二、怎么用Optimizer Trace?——四步搞定

Optimizer Trace默认是关闭的,因为开启会产生额外开销。好在它是轻量级工具,支持会话级别开启,不影响其他会话。

步骤一:开启Optimizer Trace

SET SESSION optimizer_trace = "enabled=on";
SET end_markers_in_json = ON;

end_markers_in_json=ON会在JSON输出的每个阶段添加结束标记,方便阅读。

步骤二:执行需要分析的SQL

SELECT * FROM orders WHERE customer_id = 12345 AND order_date > '2026-01-01';

步骤三:查询跟踪结果

SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G

OPTIMIZER_TRACE表有4个字段:

字段 含义
QUERY 执行的SQL语句
TRACE 优化过程的JSON格式文本(核心)
MISSING_BYTES_BEYOND_MAX_MEM_SIZE 被截断的字节数
INSUFFICIENT_PRIVILEGES 是否权限不足

步骤四:关闭Optimizer Trace

SET SESSION optimizer_trace = "enabled=off";

分析完记得关闭,避免不必要的性能开销。

三、Optimizer Trace输出结构拆解——三个核心阶段

Optimizer Trace的输出是一个JSON结构,主要包含三个阶段:

1. join_preparation(准备阶段)

这一阶段做语法解析和预处理:将*扩展为具体列、外连接转内连接、视图合并、子查询转换等。

2. join_optimization(优化阶段)——核心

这是优化器的核心工作区,也是最值得关注的部分。包含以下关键子步骤:

  • condition_processing​:WHERE和JOIN条件的优化处理
  • table_dependencies​:分析表之间的依赖关系
  • ref_optimizer_key_uses​:评估ref类型索引的使用可能
  • rows_estimation​:行数估算和成本分析

在这个阶段,你可以看到优化器为每个可能的索引计算成本,对比不同访问路径的代价,最终做出选择。

3. join_execution(执行阶段)

记录执行器实际执行的信息,如排序操作、临时表使用等。

四、真实案例:用Optimizer Trace定位执行计划跑偏的根因

场景​:一张订单表有500万行,customer_id列有索引,order_date列也有索引。执行以下查询:

SELECT * FROM orders WHERE customer_id = 12345 AND order_date > '2026-01-01';

正常情况下,这个查询应该走(customer_id, order_date)复合索引。但实际执行计划显示type=ALL,全表扫描。

从EXPLAIN看,只知道“走了全表扫描”,但不知道为什么——明明有索引,优化器却不走。

用Optimizer Trace查看详情:

SET SESSION optimizer_trace = "enabled=on";
SELECT * FROM orders WHERE customer_id = 12345 AND order_date > '2026-01-01';
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G

rows_estimation部分,可以看到优化器评估了每个索引的成本:

"rows_estimation": {
  "table": "orders",
  "range_analysis": {
    "table_scan": {
      "rows": 5000000,
      "cost": 1000000
    },
    "potential_range_indices": [
      {
        "index": "idx_customer_id",
        "usable": true,
        "chosen": false,
        "cost": 450000
      },
      {
        "index": "idx_order_date",
        "usable": true,
        "chosen": false,
        "cost": 420000
      }
    ],
    "chosen_range_access_summary": {
      "range_scan_alternatives": [],
      "chosen": "TABLE_SCAN",
      "chosen_cost": 1000000
    }
  }
}

关键发现​:

  • 全表扫描成本:约100万
  • idx_customer_id成本:约45万(但优化器认为回表成本过高)
  • idx_order_date成本:约42万

优化器最终选择了全表扫描,因为两个单列索引的回表代价都太高了——customer_id = 12345可能返回很多行,order_date > '2026-01-01'也可能返回很多行。

解决方案​:创建复合索引(customer_id, order_date),让索引同时覆盖两个条件,减少回表。

CREATE INDEX idx_customer_date ON orders(customer_id, order_date);

再跑一次EXPLAIN,type=refkey=idx_customer_date,查询从5秒降到0.05秒。

五、Optimizer Trace的使用原则

1. 不要在生产环境长期开启

Optimizer Trace会产生额外的开销,虽然影响很小,但仍不建议在生产环境长期开启。只在需要诊断疑难查询时临时开启,分析完立即关闭。

2. 结合EXPLAIN一起用

EXPLAIN提供“结论”,Optimizer Trace提供“过程”。先用EXPLAIN发现异常,再用Optimizer Trace追溯根因。

3. 关注成本估算部分

rows_estimation是最有价值的部分——它直接展示了优化器是如何计算每个候选计划的代价的。如果优化器选错了计划,这里会给出线索。

六、总结

EXPLAIN告诉你优化器“选了哪个计划”,Optimizer Trace告诉你优化器“为什么选它”。

当你遇到一个看起来不合理的执行计划时,不要直接给优化器贴“笨”的标签。打开Optimizer Trace,看看它到底是怎么算的——可能是统计信息过旧、可能是索引设计不够好、可能是某个参数影响了决策。

Optimizer Trace把优化器的“思考过程”完整地呈现了出来。读懂它,你就能从“执行计划的阅读者”升级为“优化器的理解者”。读懂Optimizer Trace输出的JSON,是DBA从“会用EXPLAIN”走向“理解优化器”的必经之路。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

相关文章
|
1月前
|
SQL JSON 移动开发
SQL派生表优化实战:从物化机制到LATERAL JOIN的完整进阶
很多人只知道“子查询改JOIN就快了”,但不知道为什么,也不知道什么时候该改、什么时候不该改。本文从派生表的物化机制出发,拆解临时表膨胀、索引失效的根因,通过真实案例对比派生表、CTE、LATERAL JOIN三种写法的性能差异,帮助读者从“知道现象”升级到“理解原理”。
|
1月前
|
存储 固态存储 关系型数据库
从月账单5万到3.5万:云数据库成本优化的完整复盘
上云本应是降本增效,但很多企业上云之后,账单反而越滚越大。实例规格买高了、历史数据堆在SSD上、测试环境没人关、过期快照没清理——每一笔费用都在悄悄累积。本文从云账单的三大“黑洞”出发,拆解云成本失控的根因,给出实例降配、冷热数据分层、僵尸资源清理三条可落地的优化路径,帮助DBA和运维工程师用数据驱动成本优化,让每一分钱都花在刀刃上。
|
1月前
|
SQL 运维 监控
慢查询日志的“高级用法”:从找慢SQL到做容量规划
慢查询日志是DBA最熟悉的工具,但大多数人只用它来找“跑得慢的SQL”。如果只做到这一步,你只用了慢查询日志20%的价值——剩下的80%是建立性能基线、预测容量瓶颈、评估优化效果、发现潜在风险。本文从慢查询日志的进阶用法出发,讲解如何通过持续记录慢查询建立性能基线、如何通过慢查询趋势预测容量瓶颈、如何将慢查询日志从“故障排查工具”升级为“容量规划工具”,帮助读者从“出了问题再查”升级到“看着趋势主动调整”。
|
1月前
|
SQL JSON 数据库
SQL性能调优进阶:从“会看执行计划”到“会诊断整个系统”
一条SQL慢,可能有一百种原因——SQL写法有问题、索引没建对、统计信息过旧、参数没调好、磁盘I/O满了、内存不够、网络抖动……很多DBA的做法是“先查SQL”,但真正的问题往往不在SQL本身。本文从“分层诊断”的思路出发,建立一套从SQL层→数据库层→操作系统层的逐层排查方法论,帮助读者在面对性能问题时不再“眉毛胡子一把抓”。
|
1月前
|
SQL 关系型数据库 MySQL
UNION vs UNION ALL:一个“ALL”字,性能差了一个数量级
UNION和UNION ALL的区别很多人知道,但INTERSECT和EXCEPT的执行机制、性能差异,以及如何用JOIN和子查询替代,很多人并不清楚。本文从集合操作的执行计划出发,拆解UNION去重的“隐形代价”、INTERSECT与INNER JOIN的本质差异、EXCEPT与NOT EXISTS的性能对比,并通过真实案例展示集合操作在业务场景中的正确用法与避坑指南,帮助读者从“会写集合操作”升级到“理解集合操作的底层逻辑”。
|
1月前
|
SQL JSON 算法
SQL执行计划的“成本模型”:读懂cost,理解优化器为什么选这个计划
EXPLAIN能告诉你优化器选了哪个执行计划,但说不出它为什么这么选——明明有索引它却走全表扫描,明明A计划更快它却选了B计划。优化器不靠猜,它靠一套成本模型(Cost Model)做决策。本文从优化器的成本模型出发,拆解cost的构成(IO_cost、CPU_cost、memory_cost),讲解如何通过EXPLAIN FORMAT=JSON和OPTIMIZER_TRACE看到优化器的“思考过程”,并通过真实案例展示优化器“算错账”的根因,帮助读者从“知道选了谁”升级到“理解为什么选它”。
|
2月前
|
存储 人工智能 关系型数据库
湖库一体:2026年数据库架构的“终极答案”还是新瓶装旧酒?
2026年6月,OceanBase发布湖库一体AI数据库,阿里云PolarDB年初已推出AI数据湖库(Lakebase),Databricks也在6月推出了LTAP架构。“湖库一体”成为2026年数据库圈最热的概念之一。本文从湖库一体的概念定义出发,拆解其技术原理,对比“湖仓一体”与“湖库一体”的差异,分析三大厂商的落地路径,并讨论这一趋势对DBA和架构师的现实意义。
|
3月前
|
人工智能 Cloud Native 关系型数据库
MySQL 8.4 LTS来了!从8.0到8.4,DBA必须知道的5个核心变化
MySQL 8.0社区版将于2026年结束生命周期,8.4 LTS作为首个长期支持版本,提供5年超长支持周期(至2031年)。本文从InnoDB并行查询、Redo Log动态容量、默认认证插件变更、参数默认值调整、云原生适配五个维度,梳理DBA升级前必须掌握的核心变化,并提供升级检查清单。
|
3月前
|
SQL 运维 自然语言处理
国产向量数据库有哪些?两大技术流派深度对比与选型指南
向量数据库是2026年数据库领域增长最快的细分赛道之一。本文从RAG应用和企业知识库的实际需求出发,系统梳理国产向量数据库的两大技术流派——独立向量数据库与融合型向量数据库,深入对比两者的架构差异、适用边界和选型逻辑。
|
3月前
|
SQL 人工智能 自然语言处理
Vibe Coding 是什么?当“感觉编程”遇上数据库
Vibe Coding是2026年编程圈最火的概念之一,指开发者通过自然语言描述“感觉”或“意图”,由AI自动生成代码、调试、优化。本文从Vibe Coding的起源讲起,分析它如何改变数据库开发方式:从手写SQL到自然语言查询、从人工调索引到AI推荐、从经验运维到智能诊断。探讨这项趋势对DBA职业的影响,并给出拥抱变化的实用建议。技术会变,但人的判断力、审美和业务理解才是长期竞争力。