全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-15 10 分钟 ✍️ juanwangdev

执行计划解读

执行计划通过EXPLAIN命令获取,展示SQL的执行路径和资源消耗。

EXPLAIN基本用法

查看执行计划

SQL
-- 基本语法
EXPLAIN SELECT ...;

-- MySQL 8.0+ 可使用EXPLAIN ANALYZE(实际执行)
EXPLAIN ANALYZE SELECT ...;

-- 格式化输出(JSON格式)
EXPLAIN FORMAT=JSON SELECT ...;

执行计划输出

SQL
EXPLAIN SELECT * FROM orders WHERE user_id = 1;

+----+-------------+--------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref   | rows | Extra |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------+
|  1 | SIMPLE      | orders | ref  | idx_user      | idx_user | 5       | const|  100 | NULL  |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-------+

id列

查询标识

SQL
id相同:同一级别,从上到下执行
id不同:子查询,id越大优先执行
id为NULL:结果集合并(UNION)

示例:
id=1: 主查询
id=2: 子查询(先执行)
id=NULL: UNION结果

select_type列

查询类型

类型说明性能影响
SIMPLE简单查询,无子查询/UNION✅ 最佳
PRIMARY外层查询正常
SUBQUERY子查询⚠️ 可能慢
DERIVED派生表(FROM子查询)⚠️ 临时表
UNIONUNION第二个查询正常
UNION RESULTUNION结果正常
DEPENDENT SUBQUERY依赖外层的子查询❌ 性能差

table列

访问的表名

SQL
EXPLAIN SELECT * FROM orders o JOIN users u ON o.user_id = u.id;

-- table列显示访问的表
-- <derived N>:派生表别名
-- <union M,N>:UNION合并结果

type列(关键)

访问类型(从优到差)

类型说明性能
system单行表(系统表)✅ 最优
const单行匹配(主键/唯一索引)✅ 最优
eq_ref唯一索引关联✅ 优
ref非唯一索引匹配✅ 好
range索引范围扫描✅ 可接受
index全索引扫描⚠️ 较慢
ALL全表扫描❌ 最差

类型示例

SQL
-- const:主键或唯一索引单值匹配
EXPLAIN SELECT * FROM orders WHERE id = 1;
-- type: const

-- ref:非唯一索引匹配
EXPLAIN SELECT * FROM orders WHERE user_id = 1;
-- type: ref

-- range:范围查询
EXPLAIN SELECT * FROM orders WHERE id BETWEEN 1 AND 100;
-- type: range

-- ALL:全表扫描(需优化)
EXPLAIN SELECT * FROM orders WHERE amount + 1 = 100;
-- type: ALL

possible_keys列

可能使用的索引

SQL
EXPLAIN SELECT * FROM orders WHERE user_id = 1 AND status = 2;

-- possible_keys: idx_user,idx_user_status
-- 查询条件涉及的两个索引都可能出现
-- 最终使用哪个由key列决定

key列

实际使用的索引

SQL
EXPLAIN SELECT * FROM orders WHERE user_id = 1;

-- key: idx_user(实际使用的索引)
-- key: NULL(未使用索引,全表扫描)
-- key: PRIMARY(使用主键索引)

key_len列

索引使用的字节数

SQL
-- 计算规则:
-- 列类型字节 + 是否NULL(1字节) + 变长列长度(2字节)

CREATE TABLE t1 (
    id INT PRIMARY KEY,          -- key_len: 4
    name VARCHAR(50),            -- key_len: 50*3+2+1=153(utf8mb4)
    status TINYINT NOT NULL,     -- key_len: 1
    INDEX idx_name(name),
    INDEX idx_status(status)
);

EXPLAIN SELECT * FROM t1 WHERE name = 'test';
-- key_len: 153

EXPLAIN SELECT * FROM t1 WHERE status = 1;
-- key_len: 1

-- 联合索引使用长度判断使用了多少列
CREATE INDEX idx_name_status ON t1(name, status);
EXPLAIN SELECT * FROM t1 WHERE name = 'test' AND status = 1;
-- key_len: 153 + 1 = 154(全部使用)

EXPLAIN SELECT * FROM t1 WHERE name = 'test';
-- key_len: 153(只使用name列)

ref列

索引匹配来源

SQL
-- const:常量值
EXPLAIN SELECT * FROM orders WHERE user_id = 1;
-- ref: const

-- 列名:另一表的列
EXPLAIN SELECT * FROM orders o JOIN users u ON o.user_id = u.id;
-- ref: u.id

-- func:函数结果
EXPLAIN SELECT * FROM orders WHERE user_id = ABS(1);
-- ref: func

rows列

预估扫描行数

SQL
EXPLAIN SELECT * FROM orders WHERE user_id = 1;

-- rows: 100(预估扫描100行)
-- 非精确值,InnoDB使用估算

-- rows越大,查询成本越高
-- 关注 rows * type 的组合判断性能

filtered列

过滤比例

SQL
-- MySQL 5.7+ EXPLAIN EXTENDED(或FORMAT=JSON)显示filtered
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE user_id = 1 AND status = 2;

-- filtered: 10.00(10%的记录满足status条件)
-- 索引扫描后WHERE过滤的比例

-- filtered较低说明还需大量过滤,可考虑扩展索引

Extra列(关键)

额外执行信息

Extra值说明性能影响
NULL正常执行✅ 正常
Using index覆盖索引✅ 好
Using whereWHERE过滤正常
Using index condition索引下推(ICP)✅ 好
Using temporary使用临时表⚠️ 可能慢
Using filesort文件排序⚠️ 可能慢
Using join bufferJOIN使用缓冲⚠️ 大表关联
Impossible WHEREWHERE条件不可能结果为空
DistinctDISTINCT优化正常

重要Extra分析

SQL
-- Using index:覆盖索引,无需回表
EXPLAIN SELECT user_id FROM orders WHERE user_id = 1;
-- Extra: Using index

-- Using index condition:索引下推
EXPLAIN SELECT * FROM orders WHERE user_id = 1 AND status LIKE '2%';
-- Extra: Using index condition

-- Using temporary:使用临时表(GROUP BY可能触发)
EXPLAIN SELECT user_id, COUNT(*) FROM orders GROUP BY status;
-- Extra: Using temporary

-- Using filesort:文件排序(ORDER BY可能触发)
EXPLAIN SELECT * FROM orders ORDER BY amount;
-- Extra: Using filesort(amount无索引)

综合分析示例

text
-- 查询语句
SELECT user_id, status FROM orders WHERE user_id = 1 ORDER BY status;

-- 创建索引
CREATE INDEX idx_user_status ON orders(user_id, status);

-- 执行计划
EXPLAIN SELECT user_id, status FROM orders WHERE user_id = 1 ORDER BY status;
-- type: ref
-- key: idx_user_status
-- rows: 100
-- Extra: Using index

-- 分析:
-- 1. 使用索引 idx_user_status
-- 2. 覆盖索引,无需回表
-- 3. ORDER BY使用索引排序,无filesort
-- ✅ 优化成功

性能判断标准

text
好的执行计划特征:
- type ≤ ref(避免ALL)
- key有值(使用索引)
- rows较小(扫描少)
- Extra有Using index(覆盖)

需要优化:
- type = ALL(全表扫描)
- rows很大(大量扫描)
- Extra有Using temporary/filesort

要点总结

  • type列决定访问效率,const最优,ALL最差
  • key列显示实际使用的索引
  • rows列预估扫描行数,值越小越好
  • Extra列提供优化信息,Using index表示覆盖索引
  • Using temporary/filesort表示需进一步优化
  • 综合分析各列判断查询性能

📝 发现内容有误?点击此处直接编辑

← 上一篇 慢查询日志与分析
下一篇 → 查询性能调优技巧
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库