当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL optimizer_trace怎样读取一次查询的优化决策

MySQL optimizer_trace怎样读取一次查询的优化决策

来源:17golang原创 2026-11-04 05:03:51 0浏览 收藏

读取一次查询的优化决策,可以在同一个 MySQL 会话启用 optimizer_trace,紧接着对目标 SQL 做 EXPLAIN,再读取 information_schema.OPTIMIZER_TRACE。先核对 QUERY 是否属于目标语句、跟踪是否截断以及权限是否足够,然后在相同查询块和计划前缀下比较候选路径、估算行数、代价与选择原因。

官方文档:https://dev.mysql.com/doc/refman/8.4/en/optimizer-tracing.html

本文以 MySQL 8.4 为范围,将这套方法理解为“会话内的优化决策记录”:EXPLAIN 帮助看选中了什么,trace 补充选择时考虑了什么。这适合解释索引、连接顺序或排序方案的取舍;实际慢在哪里还需要运行期数据。以下 SQL 为原创示例,本文未连接数据库执行,不提供虚构的 trace 输出。

先用同会话捕获一条语句

-- 使用独立诊断连接,先保存会话设置,结束时原样恢复。
SET @diag_old_trace = @@SESSION.optimizer_trace;
SET @diag_old_mem = @@SESSION.optimizer_trace_max_mem_size;
SET @diag_old_offset = @@SESSION.optimizer_trace_offset;
SET @diag_old_limit = @@SESSION.optimizer_trace_limit;

-- 示例上限为1 MiB,仅保留最近一条;实际按查询复杂度调整。
SET SESSION optimizer_trace_max_mem_size = 1048576;
SET SESSION optimizer_trace_offset = -1;
SET SESSION optimizer_trace_limit = 1;
SET SESSION optimizer_trace = 'enabled=on';

-- 假定已有shop.shipments表;EXPLAIN只观察优化,不执行目标SELECT。
-- 该查询是本次原创示例,替换成实际SQL时保留原来的条件和参数。
EXPLAIN FORMAT=JSON
SELECT shipment_id, promised_at
FROM shop.shipments
WHERE warehouse_id = 17
  AND delivery_state = 'queued'
ORDER BY promised_at
LIMIT 30;

-- 紧接着读取,不在中间运行其他待跟踪查询。
SELECT QUERY, TRACE,
       MISSING_BYTES_BEYOND_MAX_MEM_SIZE,
       INSUFFICIENT_PRIVILEGES
FROM information_schema.OPTIMIZER_TRACE;

-- 导出上面结果后恢复设置;读取窗口设置会清除已有跟踪。
SET SESSION optimizer_trace = @diag_old_trace;
SET SESSION optimizer_trace_max_mem_size = @diag_old_mem;
SET SESSION optimizer_trace_offset = @diag_old_offset;
SET SESSION optimizer_trace_limit = @diag_old_limit;

独立诊断连接能避免连接池换连接以及客户端后台语句干扰。如果在一个窗口启用,另一个窗口执行查询,即使账号一样也不是同一会话。上述写法捕获的是 EXPLAIN 所触发的优化记录,QUERY 会显示对应的 EXPLAIN 文本;不要把它描述成原 SELECT 已执行完成。若要跟踪真实 SELECT,需要评估执行成本,并把 EXPLAIN 那段替换为实际语句。

示例把采集窗口限定为最近一条,开始前设置 offset 和 limit,结束后恢复。窗口设置的变更会清除先前记录,所以必须先保存输出再恢复;采集中途随意改窗口可能丢掉目标证据。脚本在正常执行路径恢复设置,若客户端因错误中断,仍须手动完成末尾恢复,或关闭这个独立连接。

会话设置、目标语句和跟踪记录的静态归属关系
原创静态结构图:会话设置和目标语句属于同一连接,QUERY、TRACE 与完整性字段共同描述一条记录;图中没有实际运行数据。

把跟踪看作优化决策记录

面对长 JSON,先确定读者真正要回答的问题。例如示例只关心:warehouse_id 与 delivery_state 过滤后,优化器为什么采用某个访问路径,以及 ORDER BY promised_at 和 LIMIT 是否改变了取舍。先定位相应查询块与表,再阅读相关估算和候选方案,通常比从第一行开始逐字读完更有效。

跟踪按优化活动组织,包含数组和对象的嵌套关系。对象成员不应被当成严格执行时间线;同名字段可能出现在不同层级。实际可见内容受语句结构、优化器功能和版本影响,不能写一个固定路径并假定所有查询都有完全相同的节点。遇到子查询、派生表或多个连接表,先确认当前节点属于哪个查询块、表别名和计划前缀。

结构说明:https://dev.mysql.com/doc/refman/8.4/en/trace-general-structure.html

围绕同一查询块比较候选路径

阅读时保留“候选对象—估算依据—取舍原因—上下文”四项。潜在范围索引的可用性只能说明某项访问能力是否适合该处条件,不能单独证明最终计划必须选择它。考虑过的访问路径可能包含扫描、索引查找等方式,比较代价时要在同一表、同一连接前缀和同一优化分支下进行。

chosen 和 cause 应放回它所在的父节点解释。某个局部分支 chosen 为 true,不代表该索引一定成为整条查询的最终访问路径;某一优化方式出现 chosen 为 false,也不代表这个索引在所有位置都被禁止。cause 若给出的是规则适用性,就先检查条件结构;若体现成本取舍,则继续看估算行数、过滤效果及后续操作,不能一律归因于统计信息陈旧。

在示例的订单配送场景里,即使存在某个过滤索引,也应同时考虑返回列是否需要回表、排序是否另有成本、LIMIT 能否影响预期读取量。这里没有指定或声称任何索引一定获胜;需要由实际表结构和采集结果回答。cost 是优化器模型的估算值,不是毫秒,也不是“索引快几倍”的直接证据。

查询块、候选路径、估算行数与选择原因的静态关系
原创静态结构图:候选路径的取舍需要估算行数、代价和上下文共同解释;局部选择标记不等于最终计划。

官方阅读示例:https://dev.mysql.com/doc/refman/8.4/en/tracing-example.html。示例用于理解记录组织方式,不要复制其中的行数和代价作为自己的运行结果。

排除记录不完整与错误比较

MISSING_BYTES_BEYOND_MAX_MEM_SIZE 非零表示受内存上限影响有内容未保存,此时“没看到某候选”不能直接推出“优化器没有考虑”。需要在可承受范围增加会话上限并重新捕获,单纯把客户端显示宽度改大不能补回服务器已经没有记录的字节。反过来,服务器字段显示未截断,也不代表客户端导出没有被自身长度限制截短。

INSUFFICIENT_PRIVILEGES 为 1 时,可能因为涉及 SQL SECURITY DEFINER 的视图或存储例程而看不到完整信息。应按授权范围诊断,不通过放大内存解决权限问题。普通查表权限和能否看到内部跟踪不是完全相同的判断。

另一种常见反例是先执行目标 SQL,再运行几条排查查询,最后才读取 trace。默认窗口很小,留下的可能已经是别的语句。必须核对 QUERY,并在记录中保存会话上下文。存储例程含多个子语句时尤其如此,要调整捕获窗口与读取目标,不能拿最后一个子语句解释整个调用。

字段说明:https://dev.mysql.com/doc/refman/8.4/en/information-schema-optimizer-trace-table.html

保存上下文并结束跟踪

有用的诊断记录还包括 MySQL 版本、完整 SQL 与参数类型、表结构和索引定义、相关会话设置、统计信息状态及对应 EXPLAIN。改变一个因素后重新捕获,比较相同上下文里的候选取舍;若同时换参数、刷新统计和加索引,就很难解释结果由谁造成。

trace 会增加记录开销,不适合长期给所有业务查询开启。保存目标结果后恢复原设置,避免诊断状态随连接池流转。导出内容可能带查询常量和业务信息,分享时只保留解释问题所需内容。对性能结论,在关闭跟踪后用可比较负载观察耗时与运行期行数;优化器选择理由清楚,并不保证运行中没有锁等待或缓存差异。

要回答的问题优先查看不能直接推导
是否捕获目标语句QUERY 与会话归属同账号就是同连接
为何某方案被放弃候选路径、cause 与父节点局部 false 表示索引永远不可用
能否相信记录覆盖范围缺失字节、权限字段与客户端导出没有节点就没有考虑
改动是否更快关闭跟踪后的运行期比较cost 数值就是实际耗时

必须运行原 SELECT 才能得到 trace 吗?

可以先通过 EXPLAIN 观察其优化记录,尤其适合避免执行昂贵的读取;但要明确采集对象,并对实际执行表现另做比较。

为什么换个窗口读不到?

跟踪只属于当前会话。固定同一物理连接完成设置、目标语句和结果读取,再保存输出。

为什么 JSON 路径和教程不同?

版本、语句结构和启用功能都可能改变记录。先根据父节点和查询块定位,不把某次示例的数组下标做成通用解析契约。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL mysqlbinlog怎样按时间范围导出增量日志MySQL mysqlbinlog怎样按时间范围导出增量日志
上一篇
MySQL mysqlbinlog怎样按时间范围导出增量日志
MySQL 临时表怎样只在当前连接中保留数据
下一篇
MySQL 临时表怎样只在当前连接中保留数据
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    875次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    873次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    952次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    934次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    763次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码