如何看懂 MySQL 5.7 的 Explain 执行计划来做查询优化?

来源:AI大模型作者:柬埔寨程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何看懂 MySQL 5.7 的 Explain 执行计划来做查询优化?》,敬请观看详情。一条看似简单的查询在大数据量下突然变慢,往往是因为优化器选错了访问路径。Explain 是 MySQL 5.7 自带的执行计划查看工具,它能告诉我们表以什么顺序关联、是否走了索引、扫描了多少行。理解输出里的 id、select_type、type、key 和 rows 字段,是定位慢查询的第一步。比如 type 为 ALL 意味着全表扫描,而 ref 或 range 通常代表命中了索引。本文结合真实表结构和 SQL,逐一拆解各列含义,并给出改写语句、调整索引的实操思路,帮助你在没有专业监控平台时,也能靠命令行快速判断查询瓶颈所在。

在 MySQL 5.7 中,当我们怀疑某条 SQL 查询性能不佳时,最基础也最有效的手段就是在语句前加上 Explain 关键字。它能让数据库优化器把原本准备怎么执行这条语句的方案打印出来,而不是真正去跑数据。通过阅读这份“执行计划”,我们可以判断索引是否被正确使用、表之间的关联顺序是否合理,以及大概需要扫描多少行记录。

如何看懂 MySQL 5.7 的 Explain 执行计划来做查询优化?

一、Explain 的基本用法

使用方式非常简单,只需要在 SELECT 语句前面直接加上 Explain 即可,MySQL 并不会真正执行查询,只会返回执行计划。例如我们有一张用户订单表 orders 和用户信息表 users,想查看联表查询的计划,可以写成如下形式。

EXPLAIN
SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.status = 1
  AND u.age > 20;

执行后通常会得到一张包含 id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra 等列的表格。每一行代表一个被访问的表,以及该表在被优化器安排下的访问方式。在 MySQL 5.7 里,如果使用了派生表或者子查询,还会通过 id 的大小体现出嵌套层级关系。

很多人初看 Explain 容易被一堆缩写劝退,其实只要抓住几个核心字段就能解决大部分问题。比如 type 显示了访问类型,rows 显示了预估扫描行数,key 显示了实际用到的索引。这三个值往往比复杂的理论更能直观反映 SQL 的健康程度。

二、关键字段逐一拆解

1. id 与 select_type

id 列表示查询中每个 SELECT 子句或者表的执行顺序,数值越大越先执行;如果相同,则按从上到下的顺序。对于单表查询,通常只有一行且 id 为 1。如果是子查询,MySQL 5.7 可能会把子查询物化成临时表,这时候就能从 id 差异看出主次关系。

select_type 则说明该行的查询类型,常见值有 SIMPLE(普通查询)、PRIMARY(外层查询)、SUBQUERY(子查询)、DERIVED(派生表)等。理解这些类型有助于我们分析复杂 SQL 的结构,尤其是当 Explain 出现多行结果时,能快速对应到原语句的哪一部分。

2. type 访问类型

type 是判断性能强弱最核心的一栏。从优到劣常见顺序为:system、const、eq_ref、ref、range、index、ALL。其中 const 和 eq_ref 多见于主键或唯一索引的精确匹配;ref 是普通索引等值查询;range 是索引范围扫描,比如用到了 BETWEEN 或 IN;而 ALL 代表全表扫描,在大数据表上通常是需要优化的信号。

举个例子,如果 orders 表的 user_id 上有普通索引,但查询条件只过滤了 status 而没有用到 user_id,就可能出现 type 为 ALL 的情况。这时候即便返回行数不多,数据库也要先扫全表再过滤,磁盘 IO 压力很大。我们可以通过调整 WHERE 顺序或建立联合索引来改善。

3. key 与 rows

possible_keys 表示优化器认为可能用得上的索引,而 key 是它最终选中的那个。有时候 possible_keys 不为空但 key 为 NULL,说明优化器评估后觉得全表扫描比走索引更划算,常见于命中数据比例过高的场景。rows 则是预估需要读取的行数,注意它是“预估”,和实际返回行数不一定相等。

当发现 rows 数值异常大,而实际业务只需要少量数据时,往往意味着缺少合适的索引或者统计信息过期。在 MySQL 5.7 中可以用 ANALYZE TABLE 来更新表的统计信息,帮助优化器做出更好的选择。同时结合 Extra 列的 Using where、Using index 等提示,能进一步确认是否发生了回表。

三、通过案例看优化思路

1. 缺失索引导致全表扫描

假设 orders 表有百万级数据,但 status 字段没有索引,执行下面的语句时 Explain 的 type 就会是 ALL。

EXPLAIN
SELECT * FROM orders WHERE status = 1;

此时可以在 status 上建立单列索引,或者根据常用查询建立包含 status 和其他过滤字段的联合索引。建立索引后再次 Explain,通常会看到 type 变为 ref 或 range,rows 明显下降。需要注意的是,索引也不是越多越好,写操作会带来维护开销。

另外如果查询里使用了函数包裹字段,比如 WHERE YEAR(create_time) = 2023,即便 create_time 有索引也无法命中。MySQL 5.7 不支持函数索引(8.0 才支持),所以应当改写为范围查询,让优化器能用到普通 B+Tree 索引。

2. 联表顺序与驱动表选择

在多表 JOIN 时,Explain 的 rows 和表顺序暗示了优化器选谁做驱动表。一般小表驱动大表更高效。如果发现大表被放在了前面且 type 不佳,可以检查关联字段的索引情况,或者利用 STRAIGHT_JOIN 强制指定顺序,但此举需谨慎,要先对比执行时间。

EXPLAIN
SELECT *
FROM users u
STRAIGHT_JOIN orders o ON u.id = o.user_id
WHERE u.city = 'beijing';

上述写法强制 users 作为驱动表,如果 users 经过 city 过滤后只剩少量记录,那么拿这些 id 去 orders 里通过 user_id 索引查找就会非常快。通过前后两次 Explain 的对比,我们能清楚看到驱动表变化带来的 rows 差异。

四、Extra 列的隐藏信息

Extra 列经常给出关键细节。Using index 表示覆盖索引,不需要回表,性能很好;Using where 表示在取得数据后还做了过滤;Using temporary 和 Using filesort 则通常意味着排序或分组没用到索引,是大查询里需要重点关注的性能杀手。

例如一个带 ORDER BY 的查询如果 Extra 出现 Using filesort,说明排序无法利用索引顺序,只能在内存或磁盘做额外排序。此时应考虑把排序字段加入索引,或者减少排序数据量。MySQL 5.7 的 Explain 不会直接告诉你“慢”,但这些字眼就是优化入口。

五、总结与实践建议

掌握 MySQL 5.7 的 Explain 并不需要背下所有文档,核心是先看 type 排除全表扫描,再看 key 确认索引生效,最后用 rows 和 Extra 评估代价。日常写复杂 SQL 时,养成先 Explain 再上线的习惯,能避免很多线上慢查询事故。

建议把高频接口的核心语句都跑一遍 Explain,建立简单的巡检清单。当数据量增长或业务变动导致索引失效时,执行计划会第一时间露出破绽,比盲目加硬件更省钱也更治本。

MySQL_5.7Explain执行计划修改时间:2026-08-10 17:18:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。