MySQL 执行计划分析
EXPLAIN 命令展示SQL的执行计划,是诊断和优化查询性能的重要工具。
EXPLAIN 基本使用
SQL
-- 查看执行计划
EXPLAIN SELECT * FROM users WHERE name = '张三';
-- 查看完整执行计划(MySQL 8.0+)
EXPLAIN ANALYZE SELECT * FROM users WHERE name = '张三';
-- 格式化输出
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE name = '张三';
执行计划列解读
| 列 | 说明 | 关注点 |
|---|---|---|
| id | 查询标识 | 相同ID并行执行,不同ID按顺序执行 |
| select_type | 查询类型 | SIMPLE最优,SUBQUERY需关注 |
| table | 访问的表 | 确认表名 |
| partitions | 分区信息 | 分区表关注 |
| type | 访问类型 | 从system到ALL,越左越好 |
| possible_keys | 可能的索引 | 建议的索引列表 |
| key | 实际使用的索引 | 确认是否用索引 |
| key_len | 索引长度 | 越短越好 |
| ref | 索引比较值 | 哪个字段或常量 |
| rows | 预估扫描行数 | 越少越好 |
| filtered | 过滤百分比 | 越高越好 |
| Extra | 附加信息 | 关注Using index、Using temporary |
type 访问类型详解
SQL
性能排序(从好到差):
system > const > eq_ref > ref > range > index > ALL
| type | 说明 | 示例 |
|---|---|---|
| system | 单行系统表 | 系统表只有一行 |
| const | 单行常量匹配 | WHERE id = 1(主键/唯一) |
| eq_ref | 唯一索引关联 | JOIN时用主键关联 |
| ref | 非唯一索引匹配 | WHERE name = '张三' |
| range | 索引范围扫描 | WHERE id BETWEEN 1 AND 10 |
| index | 全索引扫描 | 扫描全部索引 |
| ALL | 全表扫描 | 无索引,扫描全部数据 |
SQL
-- const(最优)
EXPLAIN SELECT * FROM users WHERE id = 1;
-- type: const
-- ref(良好)
CREATE INDEX idx_name ON users(name);
EXPLAIN SELECT * FROM users WHERE name = '张三';
-- type: ref
-- range(可接受)
EXPLAIN SELECT * FROM users WHERE id BETWEEN 1 AND 100;
-- type: range
-- ALL(需优化)
EXPLAIN SELECT * FROM users WHERE age = 20; -- age无索引
-- type: ALL → 需添加索引
Extra 附加信息详解
SQL
-- Using index(覆盖索引,最优)
EXPLAIN SELECT name FROM users WHERE name = '张三';
-- Extra: Using index
-- Using where(Server层过滤)
EXPLAIN SELECT * FROM users WHERE name = '张三' AND age > 20;
-- Extra: Using where; Using index condition
-- Using temporary(临时表,需优化)
EXPLAIN SELECT DISTINCT name FROM users;
-- Extra: Using temporary → 添加索引优化
-- Using filesort(文件排序,需优化)
EXPLAIN SELECT * FROM users ORDER BY RAND();
-- Extra: Using filesort → 用索引排序
-- Using index condition(索引下推)
EXPLAIN SELECT * FROM users WHERE name LIKE '张%' AND age = 20;
-- Extra: Using index condition
-- Impossible WHERE(条件不可能)
EXPLAIN SELECT * FROM users WHERE 1 = 0;
-- Extra: Impossible WHERE
rows 与 filtered
SQL
-- rows: 预估扫描行数
-- filtered: 扫描后满足条件的百分比
EXPLAIN SELECT * FROM users WHERE name = '张三';
-- rows: 10 → 预估扫描10行
-- filtered: 100.00 → 100%满足条件
-- rows过大需优化(添加索引)
EXPLAIN SELECT * FROM users WHERE age = 20;
-- rows: 10000 → 全表扫描,需优化
id 与 select_type
SQL
-- SIMPLE(简单查询)
EXPLAIN SELECT * FROM users WHERE id = 1;
-- id: 1, select_type: SIMPLE
-- PRIMARY + SUBQUERY(子查询)
EXPLAIN SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
-- id: 1, select_type: PRIMARY
-- id: 2, select_type: SUBQUERY
-- PRIMARY + DERIVED(派生表)
EXPLAIN SELECT * FROM (SELECT id FROM users) t;
-- id: 1, select_type: PRIMARY
-- id: 2, select_type: DERIVED
-- UNION(联合查询)
EXPLAIN SELECT id FROM users UNION SELECT id FROM orders;
-- id: 1, select_type: PRIMARY
-- id: 2, select_type: UNION
-- id: NULL, select_type: UNION RESULT
执行计划分析案例
SQL
-- 案例1:全表扫描
EXPLAIN SELECT * FROM users WHERE age = 25;
-- type: ALL
-- rows: 10000
-- Extra: Using where
-- 优化:添加索引
CREATE INDEX idx_age ON users(age);
EXPLAIN SELECT * FROM users WHERE age = 25;
-- type: ref
-- rows: 50
-- key: idx_age
-- 案例2:索引失效
EXPLAIN SELECT * FROM users WHERE YEAR(create_time) = 2024;
-- type: ALL
-- Extra: Using where
-- 优化:改用范围查询
EXPLAIN SELECT * FROM users
WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';
-- type: range
-- key: idx_create_time
-- 案例3:文件排序
EXPLAIN SELECT * FROM users ORDER BY create_time;
-- type: ALL
-- Extra: Using filesort
-- 优化:添加索引
CREATE INDEX idx_create_time ON users(create_time);
EXPLAIN SELECT * FROM users ORDER BY create_time LIMIT 100;
-- type: index
-- Extra: Using index
查看实际执行统计
text
-- MySQL 8.0+ 使用 EXPLAIN ANALYZE
EXPLAIN ANALYZE SELECT * FROM users WHERE name = '张三';
-- 输出包含:
-- 实际执行时间
-- 实际扫描行数
-- 实际返回行数
-- 查看优化器追踪
SET optimizer_trace='enabled=on';
SELECT * FROM users WHERE name = '张三';
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET optimizer_trace='enabled=off';
执行计划分析是SQL优化的核心技能,定期审查慢查询的执行计划。
要点总结
- type 从 system 到 ALL,越左性能越好
- ALL 全表扫描需添加索引优化
- Extra 出现 Using temporary/filesort 需优化
- rows 越小越好,代表扫描行数
- filtered 代表过滤效率,越高越好
- MySQL 8.0 EXPLAIN ANALYZE 提供真实执行数据
📝 发现内容有误?点击此处直接编辑