MySQL Optimizer Trace 怎么查看索引选择原因
MySQL 明明有索引,优化器却选择了全表扫描或另一条索引,单看 EXPLAIN 往往只能看到“选了什么”,看不到“为什么这样选”。这时可以在同一个连接里开启 Optimizer Trace:执行原查询,再读取 INFORMATION_SCHEMA.OPTIMIZER_TRACE,从候选访问路径、估算行数和成本判断索引落选原因。
官方地址:https://dev.mysql.com/
- Optimizer Trace 只观察当前会话,开启、执行、读取、关闭必须使用同一个连接。
- 先看候选索引是否可用,再比较估算行数与成本,最后确认
chosen或cause。 - Trace 是诊断依据,不等于强制改索引;统计信息、数据分布和 SQL 写法仍要一起核对。
先用 EXPLAIN 固定要分析的查询与索引候选
建议先把线上慢 SQL 脱敏后放到测试或只读环境,用 EXPLAIN 看当前计划。下面的例子假设订单表上有 idx_status_created_at,查询希望按状态和创建时间过滤:
-- 先记录当前计划,确认实际查询与索引候选
EXPLAIN
SELECT id, user_id, created_at
FROM orders
WHERE status = 'paid'
AND created_at >= '2026-09-01'
ORDER BY created_at DESC
LIMIT 50;
如果 key 为空,或者 key 不是预期索引,先记下 possible_keys、rows、filtered 和 Extra。Trace 的任务不是替代 EXPLAIN,而是把优化器在计划生成阶段比较过的候选展开。

在当前会话开启 optimizer_trace 并执行原语句
不要只执行开启语句后换到另一个连接。官方流程要求在当前会话执行被追踪的语句;连接池场景尤其容易因为连接切换而读不到预期结果。
-- 只在当前诊断连接打开追踪,并给较大的 Trace 留出空间
SET optimizer_trace = 'enabled=on';
SET optimizer_trace_max_mem_size = 1000000;
-- 在同一连接执行要分析的原查询
SELECT id, user_id, created_at
FROM orders
WHERE status = 'paid'
AND created_at >= '2026-09-01'
ORDER BY created_at DESC
LIMIT 50;
-- 读取当前会话最近的优化器记录
SELECT QUERY, TRACE, MISSING_BYTES_BEYOND_MAX_MEM_SIZE,
INSUFFICIENT_PRIVILEGES
FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G
optimizer_trace_max_mem_size 过小,Trace 可能被截断;出现非零的 MISSING_BYTES_BEYOND_MAX_MEM_SIZE 时,先扩大诊断会话的上限再重跑。追踪结束后要执行:
-- 诊断完成立即关闭,避免这个连接继续积累 Trace
SET optimizer_trace = 'enabled=off';
从 OPTIMIZER_TRACE 读取候选路径与成本
TRACE 是 JSON 文本,不要从第一行直接跳到结论。先按下面的顺序搜索关键对象;不同 SQL 的节点组合会变化,但“可用性—估算—成本—选择”这条阅读路径比较稳定。
| 观察位置 | 重点字段 | 能回答什么 |
|---|---|---|
| 范围或访问路径分析 | index、ranges、usable | 候选索引是否能匹配谓词 |
| 行数估算 | rows、过滤比例、扫描范围 | 优化器预计要读多少数据 |
| 成本比较 | cost、cost_for_plan | 为什么某条路径在模型中更便宜 |
| 最终决策 | chosen、cause | 哪条路径胜出、其他路径为何被淘汰 |
例如,看到某索引 usable: false,方向通常是谓词无法形成有效范围、类型或排序条件不匹配;看到多个索引都可用但成本不同,就要继续对照估算行数、回表代价和排序代价。不要把“用了索引”当成“更快”的证明,Trace 记录的是优化器当时掌握的统计与成本判断。

根据 cause 与 chosen 判断索引为何落选
排查时把 Trace 当成“决策链”,而不是一串必须全部读懂的 JSON。可以先定位目标索引名称,再向上找它所在的分析对象:
- 先查可用性:如果候选索引没有进入范围分析,检查列类型、隐式转换、函数包裹、联合索引最左列和排序方向。
- 再查估算:索引可用但预计行数很大,优先核对统计信息和数据分布,不要立即用 FORCE INDEX 掩盖问题。
- 最后看成本:如果候选被
pruned_by_cost或类似原因淘汰,说明它参与过比较,只是模型认为另一条计划更便宜。
Trace 只能解释优化器的选择依据,不能直接证明真实执行耗时。结论最好与 EXPLAIN ANALYZE、表统计信息和实际数据分布交叉核对;生产环境先在低风险窗口或副本上复现。
关闭追踪并把结论落到统计信息与索引设计
如果确认是统计信息偏旧,更新统计信息后重新执行同一组 EXPLAIN 与 Trace;如果是索引列顺序或排序需求不匹配,再调整索引设计。若只是单条特殊查询,不要把 Trace 里的某个候选直接固化成全局规则。
一个可复用的检查清单是:同一连接、同一 SQL、Trace 未截断、候选索引确实可用、估算值与数据分布没有明显偏差、成本结论与实际执行计划相互印证。这样才能回答“为什么没选这条索引”,而不是只得到“加一个索引再试试”。
常见问题
Optimizer Trace 能读取其他连接执行过的 SQL 吗?
不能。官方说明它只追踪当前会话执行的语句,必须在同一个连接里开启、执行和读取。
Trace 为空是不是索引没有生效?
不一定。先确认是否换了连接、是否真的执行了目标语句,再检查追踪开关和读取权限。
为什么 Trace 里有索引但最终仍然全表扫描?
索引“可用”只表示进入了比较过程;如果估算行数或综合成本更高,它仍可能在最终决策中落选。
需要一直打开 optimizer_trace 吗?
不需要。它适合短时间诊断,读完结果就关闭,并保留 SQL、EXPLAIN 和关键 Trace 片段供复盘。
Redis GEOSEARCHSTORE 怎么保存附近对象结果
- 上一篇
- Redis GEOSEARCHSTORE 怎么保存附近对象结果
- 下一篇
- Go filepath.IsLocal 怎么筛除绝对路径和逃逸路径
-
- 数据库 · MySQL | 11小时前 |
- MySQL LATERAL 派生表怎么引用前面的表
- 252浏览 收藏
-
- 数据库 · MySQL | 13小时前 |
- MySQL Hash Join 什么时候会消耗大量内存
- 488浏览 收藏
-
- 数据库 · MySQL | 21小时前 |
- MySQL Clone 插件怎么为副本准备一致数据
- 184浏览 收藏
-
- 数据库 · MySQL | 23小时前 |
- MySQL 动态 redo 日志容量怎么设置
- 153浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL 降序索引什么时候能避免 filesort
- 110浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL SKIP LOCKED 怎么实现多消费者任务领取
- 210浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL LAST_VALUE 为什么常常不是分组最后一行
- 333浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL 直方图怎么改善倾斜列的行数估算
- 341浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 253次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 298次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 271次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 251次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 57次使用
-
- MySQL JSON_TABLE 展开数组时如何保留缺失字段
- 2026-09-10 501浏览
-
- MySQL 分区表怎么处理跨分区唯一键:分区列约束与建表取舍
- 2026-08-30 501浏览
-
- MySQL权限管理设置全攻略
- 2026-03-29 501浏览
-
- MySQL分片实现方法及常见方案解析
- 2025-06-24 501浏览
-
- MySQL表空间碎片怎么清理?超详细优化教程
- 2025-06-13 501浏览
