EXPLAIN 执行计划解读 —— type/key/rows/Extra
大家好,我是一名拥有10年以上经验的DBA老兵。
做这个系列,源于一个朴素的愿望:把踩过的坑、总结的经验系统化输出,希望能帮到刚入行或想进阶的兄弟们。
让我们开始今天的第24天内容。
昨天讲了慢查询日志——找到"谁慢"。今天讲它的续篇:看出为什么慢。
答案就是 EXPLAIN。面试必问,工作必用。能把 type 和 Extra 聊透,面试官会觉得你真干活。
怎么用
EXPLAIN SELECT * FROM users WHERE age > 30;
-- MySQL 8.0+ 还支持
EXPLAIN FORMAT=TREE SELECT ...
EXPLAIN ANALYZE SELECT ... -- 真的跑了,给实际耗时
EXPLAIN SELECT 只生成计划不跑数据。但 EXPLAIN ANALYZE 真的会跑。另外 EXPLAIN 会拿 MDL 锁,同时有 DDL 操作并发执行时会有锁等待风险。
type:你怎么找的数据?
执行计划里最核心的一列。按效率从高到低排:
| type | 含义 | 什么情况 |
|---|---|---|
const |
最多返回一行,按主键/唯一索引查 | WHERE id = 1 |
eq_ref |
连表时每行匹配一行 | JOIN 走主键 |
ref |
普通索引等值匹配 | WHERE status = 'active' |
range |
索引范围扫描 | BETWEEN、> <、IN |
index |
遍历索引树 | 比 ALL 好一点,还是遍历 |
ALL |
全表扫描 | 最差的,应该避免 |
面试最爱问 type 排序。出现 ALL 和 index 就要警惕——极小字典表全表扫描没问题,大表上出现 ALL,就是没走索引。
rows:优化器猜你要扫多少行
估算值,不是精确值。价值在看比例。
rows=500000 而你只预期几十行——索引有问题。如果估算和实际差距大,说明统计信息可能过时了,跑一下 ANALYZE TABLE。
Extra:亮点都在这里
| Extra 值 | 含义 |
|---|---|
Using index |
覆盖索引,不回表,效率极高 |
Using where |
WHERE 条件未完全被索引过滤,服务器层再判断 |
Using index condition |
索引条件下推(ICP) |
Using filesort |
无法用索引排序,需要关注 |
Using temporary |
用了临时表,常见于 GROUP BY |
Using where; Using index |
理想状态 |
判断标准:type 到 ref/range 以上,Extra 不含 filesort/temporary。
实战:看个例子
EXPLAIN SELECT * FROM orders
WHERE status = 'pending'
ORDER BY created_at DESC
LIMIT 10\G
输出里三个红色警报:
type: ALL -- 全表扫描
rows: 500000 -- 逐行比对
Extra: Using where; Using filesort -- 还要在内存里排序
瓶颈在哪?
MySQL 要先把 50 万行数据逐行读入内存,筛选出 status='pending' 的若干行,再对结果集做 filesort 排序,最后取前 10 条。IO + 排序 + 回表,三重开销。
修复:加一个复合索引
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at);
为什么是这个顺序?
B+ 树索引的叶子节点天然按 (status, created_at) 有序存储。这意味着:
- 先通过
status='pending'快速定位到索引片段(避免全表扫) - 该片段内部已经按
created_at DESC排好序(直接省略 filesort) - 取前 10 条即可收工
再看执行计划:
type: ref
rows: 50
Extra: Using where
- 扫描量:50 万 → 50,降了 1 万倍
- 排序开销:filesort 直接消失
- 唯一代价:
SELECT *还要根据主键回表查其他字段(name、price 等)
为什么 "Using where" 还在,却反而更好了?
很多人看到 Extra: Using where 就紧张,其实它只是个中性标记,表示 "Server 层会用 WHERE 条件做过滤"。真正决定性能的是:它要在多少行上做过滤,以及是否伴随其他恶性操作。
| 阶段 | 执行计划 | 实际含义 |
|---|---|---|
| 加索引前 | type: ALL + rows: 500000 + Using where; Using filesort |
先把 50 万行逐行读入内存,Server 层逐行过滤;过滤完还要在内存里排序(filesort) |
| 加索引后 | type: ref + rows: 50 + Using where |
索引直接定位到 50 行匹配数据,Server 层只在这 50 行上确认条件;排序已经由索引的有序性完成,filesort 消失 |
所以 "Using where" 没变,但它工作的上下文彻底变了:
- 优化前:它是劳动密集型——在 50 万行里大海捞针
- 优化后:它是确认型——索引已经把数据筛到 50 行了,Server 层只是做最终校验,而且省掉了 filesort 和全表 IO
如果看到
Using where就慌,那覆盖索引里的Using where; Using index你怎么解释?后者可是最佳实践。
真正该警惕的 Extra 组合是 Using where; Using filesort(全表扫 + 文件排序),而不是 Using where 本身。看 Extra 不能只看标签,要看它跟在什么 type 和 rows 后面。 ALL + Using where 是灾难,ref + Using where 是健康。
再进一步:覆盖索引
如果业务上只关心这两列,把查询改成:
SELECT status, created_at FROM orders
WHERE status = 'pending'
ORDER BY created_at DESC
LIMIT 10;
执行计划会变成:
Extra: Using where; Using index
此时连回表都省了——索引叶子节点里已经存了需要的全部数据,MySQL 不会再去碰主键索引。这就是覆盖索引。
📝 面试解答:
Q: type=index 和 ALL 哪个更差?
多数情况下 index 比 ALL 好一点——索引比数据文件小,遍历的 IO 更少。但索引不能覆盖且要回表时,
index反而比ALL更差:全扫描索引树产生大量随机回表 I/O,不如 ALL 的顺序读。所以不能只看 type,要结合 Extra 是不是Using index一起判断。
Q: Using filesort 一定会写磁盘吗?
不一定。数据量小在 sort_buffer 内存排序,超过
sort_buffer_size才写磁盘。但出现 filesort 就是需要关注了。
⚠️ 几个坑
- EXPLAIN 是估算,
EXPLAIN ANALYZE才是真实执行 - 参数绑定影响计划,分析时用具体值代替
?
🤖 AI实战工具箱:让AI当你的EXPLAIN陪练
玩法一:AI出题你来判
跟 AI 说:
你现在是 MySQL 面试官。随机生成 5 个 EXPLAIN 输出,里面有好的有坏的。每次给我一个,我判断 type 和 Extra 有没有问题,你再告诉我对不对。最后总结我的水平。
AI 可能会出这样的题:
SQL: SELECT * FROM users WHERE status = 'active'
type: ref key: status rows: 500 Extra: NULL
或这样的题:
SQL: SELECT * FROM orders ORDER BY created_at DESC LIMIT 10
type: ALL key: NULL rows: 100000 Extra: Using filesort
练完 5 道,AI 会告诉你错了几道、哪类问题老是漏判。
玩法二:没有数据库也能练
手边没 MySQL?让 AI 模拟:
假设有一张订单表 orders(id, user_id, status, amount, created_at),50 万行。status 有普通索引。给我 3 条查询加 EXPLAIN 输出,分析哪条最优、哪条最差、为什么。
AI 生成的执行计划虽然不真实,但判断逻辑是一样的。
思考题
🤔 互动时间:
- 你的业务 SQL 里有没有 type=ALL 的?今天给了你什么思路?
EXPLAIN ANALYZE和普通 EXPLAIN 什么区别?- Extra 出现
Using filesort但 SQL 没写 ORDER BY,怎么查?
总结
🎯 面试考点
- type 排序:const > eq_ref > ref > range > index > ALL
- rows 列:估算值,看比例而非绝对值
- Extra 核心:
Using index(好)、Using filesort/temporary(要优化) - EXPLAIN 是估算,
EXPLAIN ANALYZE才是真实执行 - 调优标准:type ≥ ref/range,Extra 不含 filesort/temporary
今天就试一下:找个你常用的查询,前面加 EXPLAIN 跑一遍。看一眼 type 和 Extra。如果 type=ALL 或 Extra=Using filesort——这就是你今天要优化的事。
下期预告:索引失效的典型场景 —— 面试必问!
有问题欢迎评论区交流,明天见!