MySQL EXPLAIN 结果解读
在 MySQL 中,EXPLAIN 用来查看 SQL 查询执行计划,帮助你判断查询是否使用索引、扫描了多少行、连接方式如何等,是 SQL 性能优化最重要的工具之一。
基本用法:
EXPLAIN SELECT * FROM users WHERE id = 10;
返回一个表格,每一列都有特定含义。下面是常见字段的解读。
一、EXPLAIN 输出字段说明
典型结果:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|
1 id
查询序号,表示执行顺序。
规则:
id 相同 → 按 从上到下顺序执行
id 不同 → id 越大越先执行
子查询 id 会更大
示例:
id
3
2
1
执行顺序:
3 → 2 → 1
2 select_type
表示 查询类型。
常见值:
| 类型 | 含义 |
|---|---|
| SIMPLE | 简单查询,没有子查询 |
| PRIMARY | 外层查询 |
| SUBQUERY | 子查询 |
| DERIVED | FROM 子查询(派生表) |
| UNION | UNION 后的查询 |
| UNION RESULT | UNION 结果 |
示例:
SELECT * FROM users WHERE id IN (
SELECT user_id FROM orders
);
子查询部分会显示:
SUBQUERY
3 table
当前访问的表
如果是子查询,可能显示:
<derived2>
表示临时派生表。
4 type
表示 访问类型 / 扫描方式,性能从好到差:
| type | 含义 |
|---|---|
| system | 表只有一行 |
| const | 主键或唯一索引 |
| eq_ref | 唯一索引连接 |
| ref | 普通索引 |
| range | 范围扫描 |
| index | 全索引扫描 |
| ALL | 全表扫描 |
性能排序:
system
const
eq_ref
ref
range
index
ALL
优化目标:
尽量避免:
ALL
因为是 全表扫描。
5 possible_keys
可能使用的索引
例如:
possible_keys: idx_user_id, idx_email
说明:
MySQL 认为可以使用这些索引。
但 不一定真的用。
6 key
实际使用的索引
例如:
key: idx_user_id
如果:
key: NULL
说明 没有使用索引。
7 key_len
使用的索引长度
用于判断:
是否使用了 联合索引的全部字段
例如:
联合索引:
INDEX(a,b,c)
SQL:
WHERE a=1 AND b=2
key_len 只会显示 a+b 的长度。
8 ref
表示 索引和哪个列比较。
常见:
ref: const
表示:
WHERE id = 10
或者:
ref: users.id
表示 和另一个表字段比较。
9 rows
MySQL 预估需要扫描的行数
例如:
rows: 10000
说明:
MySQL 估计需要扫描 1 万行数据。
优化目标:
rows 越小越好
10 Extra
额外信息。
常见值:
Using where
表示:
需要再进行 WHERE 过滤
不是坏事。
Using index
表示:
覆盖索引(Covering Index)
SQL 只访问索引,不访问表。
性能非常好。
Using temporary
使用 临时表。
常见于:
GROUP BY
ORDER BY
性能可能较差。
Using filesort
表示:
需要额外排序
MySQL 自己排序,而不是用索引。
例如:
ORDER BY create_time
如果 create_time 没索引,就会出现。
二、一个完整 EXPLAIN 示例
SQL:
EXPLAIN SELECT * FROM users WHERE email='a@test.com';
结果:
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | users | ref | idx_email | 1 | Using where |
解释:
type = ref→ 使用普通索引key = idx_email→ 使用 email 索引rows = 1→ 预计扫描 1 行Using where→ 还需要 WHERE 过滤
说明:
这个 SQL 性能很好
三、EXPLAIN 优化重点(实战经验)
重点关注 4 个字段:
type
key
rows
Extra
优化目标:
1 避免
type = ALL
说明:
全表扫描
2 rows 越小越好
例如:
rows = 1000000
说明扫描太多。
3 避免
Using filesort
Using temporary
4 尽量出现
Using index
说明:
覆盖索引
四、一个真实优化案例
原 SQL:
SELECT * FROM orders WHERE user_id=10;
EXPLAIN:
type: ALL
rows: 200000
说明:
没有索引
优化:
CREATE INDEX idx_user_id ON orders(user_id);
再次 EXPLAIN:
type: ref
rows: 5
性能提升 几百倍。
五、MySQL 8 推荐使用 EXPLAIN ANALYZE
在 MySQL 8+:
EXPLAIN ANALYZE SELECT ...
特点:
显示 真实执行时间
显示 真实扫描行数
比普通 EXPLAIN 更准确。