MySQL Explain 返回列详解:从入门到实战,附 SQL 与避坑大全
本文基于 MySQL 5.7+ 和 8.0+ 版本梳理,适用于大多数 MySQL 版本。建议收藏,方便日后 SQL 优化查阅。
一、Explain 是什么?
Explain 是 MySQL 提供的查询执行计划分析工具。它通过模拟优化器的执行过程,告诉你一条 SQL 语句将如何读取数据、是否使用索引、扫描多少行等关键信息,是 SQL 性能优化的“透视镜”。
核心作用
-
查看表的读取顺序:了解多表关联时谁先谁后。
-
判断索引使用情况:确认是否走索引,避免全表扫描。
-
预估查询成本:通过
rows字段估算扫描行数,定位性能瓶颈。 -
识别额外操作:发现
Using filesort(文件排序)、Using temporary(临时表)等性能杀手。
二、Explain 用法与语法
1. 基础用法(最常用)
直接在 SQL 语句前加上 EXPLAIN即可。
-- 分析单表查询
EXPLAIN SELECT * FROM user WHERE age > 18;
-- 分析多表连接
EXPLAIN SELECT u.name, o.amount
FROM user u
JOIN orders o ON u.id = o.user_id
WHERE u.city = 'Beijing';
2. 进阶用法(MySQL 8.0+)
MySQL 8.0 提供了更强大的分析能力。
-- 1. 实际执行并分析(显示实际耗时,MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT * FROM user WHERE age = 25;
-- 2. JSON 格式输出(包含更详细的成本模型数据)
EXPLAIN FORMAT=JSON SELECT * FROM user WHERE age = 25;
三、Explain 返回列详解(核心)
执行 EXPLAIN后,你会看到一张包含约 12 列的结果表。以下是每列的核心解读与实战关注点。
|
列名 |
含义 |
核心关注点 |
|---|---|---|
|
id |
查询序列号 |
判断执行顺序(id 越大越先执行) |
|
select_type |
查询类型 |
区分简单查询、子查询、UNION |
|
table |
访问的表名 |
当前行数据属于哪张表 |
|
partitions |
匹配的分区 |
若为分区表,显示命中的分区 |
|
type |
访问类型 |
性能关键!(如 const, ref, ALL) |
|
possible_keys |
可能使用的索引 |
优化器理论可选的索引 |
|
key |
实际使用的索引 |
实际走的索引(NULL 表示未走索引) |
|
key_len |
索引长度 |
判断联合索引中实际使用了多少列 |
|
ref |
索引引用 |
显示与索引比较的列或常量 |
|
rows |
预估扫描行数 |
越小越好,是估算值 |
|
filtered |
过滤百分比 |
表示条件过滤后剩余数据的比例 |
|
Extra |
额外信息 |
性能优化的关键提示(如 Using index) |
四、核心列深度解析(附 SQL 示例)
1. type列:访问类型(性能核心)
type表示 MySQL 如何查找表中的行,性能从优到劣排序如下:
|
类型 |
含义 |
示例 SQL(假设有索引) |
|---|---|---|
|
system |
表只有一行(系统表) |
|
|
const |
最优,通过主键/唯一索引一次找到 |
|
|
eq_ref |
多表 JOIN 时,被驱动表使用主键/唯一索引 |
|
|
ref |
常见,使用普通索引等值匹配(可能多行) |
|
|
range |
索引范围扫描(BETWEEN, IN, >, <) |
|
|
index |
全索引扫描(遍历索引树) |
|
|
ALL |
全表扫描(性能最差,需优化) |
|
优化建议:生产环境至少应达到 range级别,尽量避免 ALL(全表扫描)。
2. key与 possible_keys:索引使用
-
possible_keys:理论上可能用到的索引(仅供参考)。
-
key:实际使用的索引。
常见问题分析:
-
key为 NULL:说明未使用索引,需检查查询条件或建索引。 -
possible_keys有值但key为 NULL:通常因为数据量小或索引区分度低,优化器认为全表扫描更快。
3. Extra列:额外信息(优化关键)
Extra列提供了极其重要的性能线索。
|
值 |
含义 |
优化建议 |
|---|---|---|
|
Using index |
覆盖索引(极佳) |
查询列全在索引中,无需回表。 |
|
Using where |
使用 WHERE 过滤 |
正常情况,表示在存储引擎层或 Server 层进行了过滤。 |
|
Using filesort |
文件排序(需优化) |
无法利用索引排序,需额外排序操作。考虑为 |
|
Using temporary |
临时表(需优化) |
常见于 |
|
Using join buffer |
使用连接缓存 |
连接条件未使用索引,导致使用内存缓存。 |
4. rows与 filtered:扫描成本
-
rows:MySQL 预估需要扫描的行数(估算值,非精确值)。越小越好。
-
filtered:表示经过
WHERE条件过滤后,剩余行数的百分比。rows * filtered可估算连接查询中下一张表需要处理的行数。
五、实战案例:SQL 优化前后对比
场景:无索引导致全表扫描(type=ALL)
问题 SQL:
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
执行计划分析:
|
id |
type |
key |
rows |
Extra |
|---|---|---|---|---|
|
1 |
ALL |
NULL |
10000 |
Using where |
诊断:type=ALL表示全表扫描,key=NULL表示未使用索引,rows=10000表示扫描了 1 万行,性能极差。
优化方案:为 user_id添加索引。
CREATE INDEX idx_user_id ON orders(user_id);
优化后执行计划:
|
id |
type |
key |
rows |
Extra |
|---|---|---|---|---|
|
1 |
ref |
idx_user_id |
1 |
Using index |
优化效果:type从 ALL提升为 ref(索引等值匹配),rows从 10000 降为 1,性能提升千倍。
六、总结:Explain 分析 checklist
-
看
type:是否出现ALL(全表扫描)?必须优化。 -
看
key:是否实际使用了索引?key不应为 NULL。 -
看
Extra:是否出现Using filesort或Using temporary?这两个是性能杀手,需通过调整索引或 SQL 写法消除。 -
看
rows:预估扫描行数是否过大?过大说明索引可能失效或缺失。
版权声明:本文为 CSDN 博主原创,转载请注明出处。如有疑问,欢迎评论区交流。
参考来源:MySQL 官方文档、腾讯云开发者社区、脚本之家等。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)