MySQL 执行计划 EXPLAIN 详解
写SQL谁都会,但写出高效的SQL就需要点本事了。EXPLAIN 是 MySQL 提供的 SQL 分析神器,学会用它,优化速度能提升好几个量级。
什么是执行计划?
当你执行一条 SELECT 语句时,MySQL 优化器会决定用哪种查询方式——走索引还是全表扫描?关联顺序怎么选?这些决策的依据就是执行计划。
EXPLAIN SELECT * FROM user WHERE id = 1;
这行命令会告诉你:这条查询有没有走索引、用了哪个索引、扫描了多少行等等。
EXPLAIN 输出详解
EXPLAIN 的输出有十几列,最重要的有这几个:
| 列名 | 说明 |
|---|---|
| id | 查询序号,越大越先执行 |
| select_type | 查询类型 |
| table | 查询的表 |
| type | 访问类型(最重要) |
| possible_keys | 可能用到的索引 |
| key | 实际用到的索引 |
| key_len | 索引长度 |
| rows | 预计扫描行数 |
| Extra | 额外信息 |
type:访问类型(最重要!)
这一列直接反映查询效率,从最优到最差排序:
| type 值 | 含义 | 说明 |
|---|---|---|
| const | 常量查询 | 用主键或唯一索引,只扫描1行 |
| eq_ref | 唯一索引扫描 | 关联时用主键或唯一索引 |
| ref | 非唯一索引扫描 | 用普通索引,扫描多行 |
| range | 范围查询 | 索引范围扫描(between、>、<) |
| index | 全索引扫描 | 遍历整个索引树 |
| ALL | 全表扫描 | 最糟糕,需要遍历全部数据 |
实战例子:
-- const:最优
EXPLAIN SELECT * FROM user WHERE id = 1; -- 主键查询
-- ref:较好
EXPLAIN SELECT * FROM user WHERE age = 25; -- 普通索引
-- range:还可以
EXPLAIN SELECT * FROM user WHERE id > 100 AND id < 200; -- 范围查询
-- index:一般
EXPLAIN SELECT id FROM user; -- 只查索引列
-- ALL:最差!
EXPLAIN SELECT * FROM user WHERE name = 'Tom'; -- 没有索引
key:实际用的索引
EXPLAIN SELECT * FROM user WHERE age = 25 AND name = 'Tom';
输出:
| table | possible_keys | key |
|-------|--------------|----------|
| user | idx_age_name | idx_age |
possible_keys:可能用到的索引(优化器觉得能用哪些)-
key:实际用到的索引(优化器决定用哪个)
有时候possible_keys有值,但key是 NULL,说明索引失效了。
rows:预计扫描行数
这一列估计要扫描多少行数据。数值越小越好。
EXPLAIN SELECT * FROM user WHERE age > 20;
如果 rows = 1000000,说明要扫100万行——这肯定有问题,得加索引或者优化SQL。
Extra:额外信息
这个列包含很多关键信息,常见的有:
Using filesort(⚠️ 危险!)
需要额外排序,filesort 是 MySQL 的额外排序算法,效率低。
EXPLAIN SELECT * FROM user ORDER BY created_at;
解决方案:在排序字段上建索引。
Using index(✅ 好!)
直接用索引就返回数据,不需要回表。
EXPLAIN SELECT id, name FROM user WHERE id > 10;
Using where(普通)
使用了 WHERE 条件过滤。
Using index condition(⚠️ 注意)
用了索引下推(Index Condition Pushdown),比回表好,但不是最优。
Using temporary(⚠️ 危险!)
需要创建临时表,效率低。
EXPLAIN SELECT name, COUNT(*) FROM user GROUP BY name;
优化思路:考虑用索引覆盖,或者改写SQL。
Using index & Using where
同时出现说明用索引完成了过滤和返回,是比较理想的状态。
关联查询的执行计划
关联查询(JOIN)的执行计划会显示多条记录,因为涉及多个表:
EXPLAIN
SELECT u.*, o.*
FROM user u
INNER JOIN order o ON u.id = o.user_id
WHERE u.age > 20;
id:执行顺序
- id 相同,从上到下执行
-
- id 不同,id 大的先执行
-
- id 为 NULL,先执行临时表
select_type:查询类型
| 值 | 说明 |
|---|---|
| SIMPLE | 简单查询,不含子查询和 UNION |
| PRIMARY | 主查询,最外层 |
| SUBQUERY | 子查询 |
| DERIVED | 派生表(FROM 子查询) |
| UNION | UNION 后的查询 |
| UNION RESULT | UNION 结果 |
实战:分析一条慢SQL
原始SQL
SELECT *
FROM order
WHERE user_id = 100
AND status = 'pending'
ORDER BY created_at DESC
LIMIT 10;
EXPLAIN 分析
EXPLAIN
SELECT *
FROM order
WHERE user_id = 100
AND status = 'pending'
ORDER BY created_at DESC
LIMIT 10;
假设输出
| id | select_type | table | type | possible_keys | key | rows | Extra |
|----|-------------|-------|------|--------------|---------|------|---------------------|
| 1 | SIMPLE | order | ref | idx_user_id | idx_user_id | 5000 | Using where; Using filesort |
问题诊断
- type = ref:还行,用了索引
-
- rows = 5000:要扫5000行,有点多
-
- Using filesort:需要额外排序,效率低
优化方案
建一个联合索引 (user_id, status, created_at):
CREATE INDEX idx_user_status_created ON order(user_id, status, created_at);
优化后
| id | select_type | table | type | possible_keys | key | rows | Extra |
|----|-------------|-------|------|--------------|--------------------------|------|-------|
| 1 | SIMPLE | order | ref | idx_user_status_created | idx_user_status_created | 10 | Using index |
- rows 从 5000 降到 10
-
- 用到索引覆盖,不需要 filesort
-
- Extra 显示 Using index,完美!
小技巧
1. 查看索引使用情况
SHOW INDEX FROM user;
2. 查看表结构
SHOW CREATE TABLE user;
3. 强制使用索引
SELECT * FROM user FORCE INDEX (idx_age) WHERE age = 25;
⚠️ 谨慎使用,强制索引可能导致更差的执行计划。
4. 查看详细执行计划(MySQL 8.0+)
EXPLAIN ANALYZE SELECT * FROM user WHERE id = 1;
会显示实际执行时间和开销,比 EXPLAIN 更精确。
总结
| 指标 | 理想值 | 说明 |
|---|---|---|
| type | const/eq_ref/ref | 避免 ALL |
| key | 非 NULL | 必须用索引 |
| rows | 越小越好 | 扫描行数 |
| Extra | Using index | 避免 Using filesort/temporary |
EXPLAIN 是 SQL 优化的第一步,也是最关键的一步。拿到一条慢SQL,先 EXPLAIN 看看执行计划,问题基本就清楚了一半。
相关阅读:
- [MySQL 索引底层 B+ 树原理]
-
- [MySQL 慢查询优化实战]
-
- [MySQL 索引失效的七种情况]
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)