⭐ 推荐:社区规则条款 V1.0

如何读懂 MySQL 执行计划,重点该看哪些字段?

GJ
GJ 资深会员 👑黑卡会员
发布于 2026-10-26 22:13 ·4 浏览 ·0 回复
内容摘要

读懂MySQL执行计划应依次关注id与select_type判断执行顺序、type判断访问类型、possible_keys/key/key_len/ref确认索引使用,并结合rows与成本判断慢SQL是未走索引、过滤差还是排序或临时表导致;

学完这篇你会看清 EXPLAIN 结果里哪些字段是“必须看的”,以及每种取值背后代表什么样的执行代价,从而判断一条慢 SQL 到底是没走索引、索引走了但过滤差,还是排序、临时表拖了后腿。

第一步:先拿到执行计划,别急着下结论

这一步要做的,是把 SQL 交给优化器,让它输出执行计划;做完你手上会有一张或几张字段表。在 MySQL 客户端里,直接在你平时跑 SQL 的地方执行下面的语句:

EXPLAIN SELECT * FROM article WHERE category_id = 3 ORDER BY created_at DESC LIMIT 20;

MySQL 8.0 及以上还支持 EXPLAIN ANALYZE SELECT ...,它会真正执行语句并给出实际耗时与实际行数,比纯估算更准确。EXPLAIN FORMAT=JSON SELECT ... 则能拿到更细的 cost 信息。

注意:EXPLAIN 本身不执行查询(EXPLAIN ANALYZE 会真的执行),所以对写操作或大表做分析时先用 EXPLAIN,别一上来就用 ANALYZE。

第二步:看 id 和 select_type,理清执行顺序

这一步是搞清楚这条 SQL 被拆成了几块、谁先谁后。id 越大越先执行,id 相同的从上往下执行;select_type 常见取值是 SIMPLE(无子查询或 UNION)、PRIMARY(最外层)、SUBQUERY(子查询里的第一个 SELECT)、DERIVED(派生表,即 FROM 里的子查询)、UNION。

看到 DERIVED 就要警惕:派生表通常会被物化成临时表,数据量大时开销明显。

第三步:看 type,这是最该先扫一眼的字段

type 表示访问类型,直接反映索引使用的好坏。从好到坏大致是:

system > const > eq_ref > ref > range > index > ALL

  • const / eq_ref:主键或唯一索引等值命中,通常只返回一行,最理想。
  • ref:普通索引等值匹配,常见且可接受。
  • range:索引范围扫描,BETWEEN、>、IN 常见,一般可以接受。
  • index:扫整个索引树,虽然用了索引但等于全扫,数据量大时很慢。
  • ALL:全表扫描,最常见的性能杀手。

注意:type 为 ALL 不一定就是错的。小表、或者 WHERE 条件本身就要取大部分行时,全表扫描反而更快。要结合 rows 判断,而不是看到 ALL 就加索引。

第四步:看 key、key_len、possible_keys、ref,确认索引到底用了没

这一步回答“优化器本来能选哪些索引、实际选了哪个、用了几列”。possible_keys 是候选索引,key 是最终选中的索引(为 NULL 就是没走索引),ref 显示和索引做比较的列或常量,key_len 表示实际使用的索引字节数。

key_len 是判断联合索引“用了几列”的关键:联合索引 (a, b, c),如果 key_len 只等于 a 那一列的长度,说明 b、c 没被用上,多半是中间断了(比如 b 用了范围查询,或 c 上做了函数运算)。

注意:key 为 NULL 而 possible_keys 有值,说明优化器算过成本后主动放弃了索引,常见于条件区分度太低、或者回表成本高于全表扫描。这时该考虑的是覆盖索引,而不是硬加 FORCE INDEX。

第五步:看 rows 和 filtered,估算真实数据量

rows 是优化器估算的需要扫描的行数,filtered 是这些行经过 WHERE 条件过滤后剩下的百分比。两者相乘,大致就是参与后续步骤的行数。

判断标准很直接:rows 越小越好;rows 很大而 filtered 很低(比如 5%),说明索引只帮你缩小了一部分范围,剩下的仍要逐行判断,这类查询往往是“索引建了但不够精准”。MySQL 8.0 的统计信息由 InnoDB 采样生成,不准时可以执行 ANALYZE TABLE 表名; 刷新。

第六步:看 Extra,问题基本都写在这

Extra 里的提示直接点名了性能隐患,重点看这几个:

  • Using index:覆盖索引,不用回表,是好信号。
  • Using where:服务层还要再过滤,配合高 rows 就要警惕。
  • Using index condition:索引下推(ICP)生效,通常比纯 Using where 好。
  • Using filesort:需要额外排序,没利用上索引顺序。ORDER BY 的列和索引顺序不一致时必现。
  • Using temporary:用了临时表,常见于 GROUP BY、DISTINCT、UNION,数据量大时很慢。

注意:Using filesort 不等于用了磁盘文件,内存里排序也叫这个名字;但它确实意味着多一次排序开销,能靠调整索引顺序消掉就消掉。

小结

  • 先看 type,ALL 和 index 是最该优化的两种访问类型,但要结合 rows 判断,小表全扫不算问题。
  • 再看 key 和 key_len,key 为 NULL 说明没走索引;key_len 判断联合索引实际用到了第几列。
  • rows × filtered 估算真实参与行数,两个数一起看才有意义。
  • Extra 里抓 Using filesort、Using temporary、Using where 这三个信号,Using index 是好消息。
  • 需要真实数据时用 EXPLAIN ANALYZE(MySQL 8.0+),而不是只靠估算值下判断。
本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2596.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~