MySQL Explain 主要看哪些字段?
简化版
Explain 主要看访问类型 type、使用的索引 key、扫描行数 rows、过滤比例 filtered 和额外信息 Extra。面试回答要强调:Explain 是优化器估算出的执行计划,不是 SQL 实际耗时本身,要结合真实数据量、索引和执行耗时一起判断。
详细版
常看的字段有:
id:查询块编号,复杂 SQL 中用于看执行层次。select_type:普通查询、子查询、派生表等类型。table:当前访问的表或派生表。type:访问方式,常见从好到差大致是const、eq_ref、ref、range、index、ALL。possible_keys:优化器认为可能用到的索引。key:实际选择的索引。key_len:使用到的索引长度,可辅助判断联合索引用了几列。rows:预计扫描行数,越大风险越高。filtered:预计过滤后剩余比例。Extra:额外信息,比如Using index、Using where、Using filesort、Using temporary。
重点不是背字段,而是能通过 Explain 判断:有没有走合适索引、扫描范围是否过大、是否发生额外排序或临时表、联合索引是否用完整。
完整版教学
一、Explain 解决的是什么问题
Explain 用来观察 MySQL 优化器打算怎么执行一条 SQL。它能告诉你访问了哪些表、选了哪个索引、预计扫描多少行、是否需要排序或临时表。
但它不是性能报告。它是优化器基于统计信息做出的估算,可能和真实执行有偏差。真正排查慢 SQL 时,Explain 是入口,还要结合慢日志、真实耗时、数据分布和必要时的 EXPLAIN ANALYZE。
面试回答 Explain,要避免背字段表。更好的主线是:这条 SQL 从哪张表开始,怎么访问,每一步预计扫多少数据,过滤后剩多少,是否还要排序、临时表或回表。Explain 像是医生看片子,能看到结构性风险,但不能替代真实体检数据。
看 Explain 的顺序:
table -> type -> possible_keys/key/key_len -> rows/filtered -> Extra
二、type 字段怎么看
type 表示访问方式,是 Explain 里最常被问的字段:
| type | 含义 | 常见场景 |
|---|---|---|
const | 最多匹配一行 | 主键或唯一索引等值 |
eq_ref | 联表时每次最多匹配一行 | 被驱动表用唯一索引关联 |
ref | 非唯一索引等值匹配 | 普通索引等值查询 |
range | 范围扫描 | between、>、in |
index | 扫描整个索引 | 全索引扫描 |
ALL | 全表扫描 | 没有合适索引或优化器认为全表更划算 |
不是所有 ALL 都必然错误,小表全表扫描可能很正常;也不是所有 range 都一定好,如果范围很大,扫描成本也会很高。
可以用两个数字例子体会:一张配置表只有 20 行,type=ALL 扫 20 行非常正常;一张订单表 2000 万行,type=range 但 rows=8000000,仍然可能是慢 SQL。type 表示访问方式,不直接等于性能好坏,必须和数据量、选择性、返回列一起看。
三、key、key_len 和 rows 要一起看
key 表示实际用到的索引。如果 possible_keys 有值但 key 是 NULL,说明优化器最终没选这些索引,可能是统计信息、选择性或回表成本导致。
key_len 可以辅助判断联合索引用到了哪些列。比如 (a, b, c) 只用了 a,那可能是 b 的条件写法导致索引中断。
rows 是预计扫描行数。优化 SQL 时,最直接的目标通常是减少不必要扫描。如果 rows 很大,即使走了索引,也可能是低效索引扫描。
key_len 常被用来辅助判断联合索引用到了几列,但不要把它当成绝对答案,因为字段类型、是否允许 NULL、字符集都会影响长度。更稳妥的说法是:它能帮助推断索引使用前缀,再结合 SQL 条件和 Extra 判断是否被范围条件、函数或隐式转换截断。
| 字段组合 | 该看什么 | 典型判断 |
|---|---|---|
possible_keys 有,key 为 NULL | 优化器没选索引 | 可能全表更便宜或统计信息有偏 |
key 命中但 rows 很大 | 索引选择性不足 | 走索引不等于高效 |
key_len 偏短 | 联合索引可能只用前几列 | 检查最左前缀和范围条件 |
filtered 很低 | 后续过滤掉大量记录 | 可能需要更合适的联合索引 |
易错点:Explain 要成组看字段,单看
type或key都容易误判。
四、Extra 里的高频信号
常见 Extra 信息:
Using index:覆盖索引,查询列可直接从索引返回。Using where:Server 层还要继续判断where条件。Using index condition:使用索引下推,存储引擎层先判断部分索引条件。Using filesort:需要额外排序,不一定真的落磁盘,但通常要关注。Using temporary:使用临时表,常见于复杂分组、排序、去重。
Using filesort 和 Using temporary 不是见到就必须消灭,但如果 SQL 高并发、数据量大,就要重点分析是否能通过索引顺序、改写 SQL 或减少返回数据来优化。
Using filesort 的名字容易误导,它不等于“一定写磁盘文件”,而是表示 MySQL 需要额外排序过程。小结果集排序可能在内存里完成,成本可接受;大结果集排序、高并发排序,才是风险。Using temporary 也类似,复杂 group by、distinct、排序组合都可能触发临时表,要结合行数和频率判断。
-- 如果有索引 (user_id, create_time),这个查询更可能避免额外排序
select *
from orders
where user_id = 1001
order by create_time desc
limit 20;
五、联表 Explain 要看驱动顺序
联表查询还要关注表访问顺序。优化器会选择驱动表和被驱动表,理想情况通常是先用过滤条件强的表缩小结果,再用索引关联另一张表。eq_ref 常出现在被驱动表通过主键或唯一索引关联时,说明每次关联最多匹配一行。
例如订单表和用户表关联,如果先从订单表按时间筛出 100 条,再用用户主键查用户信息,成本很低;如果先扫 1000 万用户再关联订单,就很可能不合理。Explain 的每一行不是孤立看的,行与行之间的访问顺序也很关键。
六、Explain 之后怎么优化
Explain 只是定位方向,不是自动给答案。看到 rows 大,可以考虑更合适的联合索引、条件改写、减少返回列;看到 Using filesort,可以考虑让索引顺序覆盖排序;看到 Using temporary,可以检查分组字段和排序字段是否能减少数据量;看到 key=NULL,要看是否存在函数、隐式转换、前置模糊匹配或统计信息问题。
优化前后要对比同一数据量下的 Explain 和真实耗时。MySQL 8.0 的 EXPLAIN ANALYZE 能给出实际执行统计,但它会真正执行 SQL,在线上使用要谨慎。普通面试回答可以说:Explain 看计划,慢日志看真实慢,必要时压测或在影子环境验证。
七、常见误区与追问
- 误区:
type=ALL就一定是坏计划。 小表、低选择性查询或返回大部分数据时,全表扫描可能比走索引再大量回表更便宜。 - 误区:看到
key有值就说明 SQL 没问题。 还要看rows、filtered和Extra,低选择性索引扫描大量记录一样会慢。 - 误区:
Using filesort表示一定发生磁盘文件排序。 它表示额外排序过程,是否落盘取决于数据量、内存和执行情况。 - 误区:Explain 的
rows就是真实扫描行数。 它是基于统计信息的估算,可能和真实执行有偏差。 - 追问:联合索引用了几列怎么看? 可以结合
key、key_len、where 条件和Extra推断,但不能只靠key_len机械判断。 - 追问:Explain 优化 SQL 的主线是什么? 看访问路径是否合理、索引是否匹配、扫描行数是否可控、是否有额外排序或临时表,再决定索引和 SQL 改写。
八、加强记忆
Explain 要围绕“访问路径”读:先看访问哪张表,再看 type 判断访问方式,看 key/key_len 判断索引选择和使用前缀,看 rows/filtered 判断扫描与过滤成本,最后看 Extra 捕捉覆盖索引、索引下推、排序和临时表。它是优化入口,不是最终性能结论;真正靠谱的判断,要把执行计划、数据量、慢日志和实际耗时放在一起。