如何查看 SQL 的执行计划
查看 SQL 执行计划是 “优化 SQL 性能” 的核心步骤,通过EXPLAIN命令可获取 MySQL 优化器生成的执行计划,了解 SQL 的执行方式(如是否使用索引、扫描行数、关联顺序等),从而定位性能瓶颈。
# 1. 基本用法
在查询 SQL 前添加EXPLAIN关键字,即可查看执行计划:
-- 查看单表查询执行计划
EXPLAIN SELECT * FROM user WHERE age > 20;
-- 查看多表关联查询执行计划
EXPLAIN SELECT u.name, o.order_id FROM user u JOIN `order` o ON u.id = o.user_id WHERE u.age > 20;
1
2
3
4
5
2
3
4
5
# 2. 执行计划核心字段解析
执行计划返回的字段中,关键字段如下(重点关注带★的字段):
| 字段名 | 核心含义 |
|---|---|
| ★ id | 执行顺序标识:id 相同,按从上到下顺序执行;id 不同,id 越大优先级越高(子查询先执行) |
| ★ select_type | 查询类型:SIMPLE(简单查询,无子查询)、SUBQUERY(子查询)、DERIVED(派生表)、JOIN(关联查询) |
| ★ table | 执行查询的表(或派生表别名、子查询别名) |
| ★ type | 访问类型(索引使用效率):从优到差为 system > const > eq_ref > ref > range > index > ALL |
| ★ possible_keys | 可能使用的索引(MySQL 认为适合的索引) |
| ★ key | 实际使用的索引(若为 NULL,说明未使用索引,可能全表扫描) |
| key_len | 实际使用的索引长度(越长,索引过滤性越好) |
| ★ rows | MySQL 预估的扫描行数(越少,性能越好) |
| ★ Extra | 额外信息(如 Using index:覆盖索引、Using where:使用 WHERE 过滤、Using filesort:文件排序、Using temporary:临时表) |
# 3. 关键字段详解
# (1)type 字段(访问类型,核心关注)
- system:表中只有一行数据(如系统表),性能最优;
- const:通过主键或唯一索引查询,只返回一行数据(如
WHERE id=1); - eq_ref:多表关联时,被驱动表通过主键或唯一索引匹配(如
user.id = order.user_id,order 表的 user_id 是主键); - ref:通过非唯一索引匹配(如
WHERE name='张三',name 是普通索引); - range:索引范围查询(如
WHERE age BETWEEN 20 AND 30、WHERE id IN (1,2,3)); - index:扫描整个索引(如
SELECT id FROM user,id 是索引,无需访问数据文件); - ALL:全表扫描(性能最差,需优化,如添加索引)。
# (2)Extra 字段(额外信息,核心关注)
- Using index:覆盖索引(查询字段均在索引中,无需回表),性能好;
- Using where:使用 WHERE 子句过滤数据(索引未过滤全部数据,需在内存中过滤);
- Using filesort:文件排序(未使用索引排序,需在磁盘或内存中排序,性能差,需优化索引,如
ORDER BY字段添加索引); - Using temporary:创建临时表(如
GROUP BY未使用索引,需创建临时表存储分组结果,性能差); - Using join buffer:关联查询时使用连接缓冲区(被驱动表未使用索引,需缓存驱动表数据匹配,性能差);
- Impossible WHERE:WHERE 条件恒假(如
WHERE 1=2),无数据返回。
# 4. 执行计划分析示例
示例 SQL:EXPLAIN SELECT * FROM user WHERE age > 20 AND name LIKE '张%'
执行计划结果(关键字段):
| id | select_type | table | type | possible_keys | key | rows | Extra |
|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | user | range | idx_age_name | idx_age_name | 100 | Using where |
分析:
- type=range:使用索引范围查询(age>20+name LIKE ' 张 %',匹配索引
idx_age_name); - key=idx_age_name:实际使用了联合索引
idx_age_name(age 在前,name 在后,符合最左前缀原则); - rows=100:预估扫描 100 行,性能较好;
- Extra=Using where:索引过滤后,需进一步过滤数据(无问题)。
若执行计划中 key=NULL、type=ALL,说明未使用索引,需添加索引(如CREATE INDEX idx_age_name ON user(age, name))。
# 5. 扩展:EXPLAIN EXTENDED(查看优化后的 SQL)
EXPLAIN EXTENDED可查看 MySQL 优化器改写后的 SQL(如简化条件、改写关联顺序),帮助理解优化逻辑:
EXPLAIN EXTENDED SELECT * FROM user WHERE age > 20 AND age < 30;
-- 执行后,通过SHOW WARNINGS查看改写后的SQL
SHOW WARNINGS;
1
2
3
2
3
#
上次更新: 12/30/2025