首页 > 数据库    日期:2026-07-03 / 浏览

EXPLAIN 是 MySQL 提供的查询执行计划分析工具,在 SELECT 语句前加上 EXPLAIN 即可查看优化器如何执行 SQL。执行结果包含 12 个核心字段。

一、执行顺序相关字段

字段 含义 核心要点
id 查询序列号,标识 SELECT 的执行顺序 ① id 相同 → 从上往下顺序执行
② id 不同 → id 值越大越先执行(子查询 id 递增)
③ id 为 NULL → 最后执行(如 UNION RESULT)
select_type 查询类型,区分简单/复杂查询 见下方详细分类
table 当前访问的表名 派生表显示为 <derived N>,UNION 显示为 <union M,N>
partitions 匹配的分区 仅分区表有效,否则为 NULL

select_type 取值详解

含义 示例
SIMPLE 简单查询,无子查询/UNION SELECT * FROM t1 WHERE id=1
PRIMARY 最外层查询(含子查询时) 包裹子查询的外层 SELECT
SUBQUERY SELECT 或 WHERE 中的子查询 SELECT * FROM t1 WHERE id IN (SELECT id FROM t2)
DEPENDENT SUBQUERY 依赖外部查询的子查询 子查询引用了外层表的列
DERIVED FROM 子句中的子查询(派生表) SELECT * FROM (SELECT * FROM t1) a
UNION UNION 中第二个及之后的 SELECT SELECT * FROM t1 UNION SELECT * FROM t2
DEPENDENT UNION 依赖外部查询的 UNION UNION 子查询引用外层表
UNION RESULT UNION 的结果合并 id 通常为 NULL
MATERIALIZED 物化的子查询(MySQL 8.0+) 子查询结果缓存为临时表

📌 优先级排序:SIMPLE > PRIMARY > UNION/SUBQUERY/DERIVED > DEPENDENT SUBQUERY/DEPENDENT UNION

二、索引与访问方式(⭐ 核心重点)

字段 含义 说明
type 访问类型/连接类型 ⭐ 性能核心指标,从优到差排序见下方
possible_keys 可能使用的索引 优化器的"备选方案",不一定实际使用
key 实际使用的索引 为 NULL 表示未使用索引
key_len 索引使用的字节数 判断联合索引用了几列,计算规则见下方
ref 索引与谁比较 const(常量)、字段名、func 等
rows 预估扫描行数 越小越好,基于统计信息的估算值
filtered 过滤后剩余比例(%) 最终行数 ≈ rows × filtered / 100
Extra 额外执行信息 ⭐ 性能问题的"信号灯",见下方

🔥 type 访问类型(从最优到最差)

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge >
unique_subquery > index_subquery > range > index > ALL
类型 含义 场景 性能
system 表只有一行记录(const 特例) 系统表、LIMIT 1 且只有一行 ⭐⭐⭐⭐⭐
const 主键/唯一索引等值查询,最多1行 WHERE id = 1、WHERE pk IN (1) ⭐⭐⭐⭐⭐
eq_ref 唯一索引关联,每行最多匹配1行 JOIN 时被驱动表用主键/唯一索引关联 ⭐⭐⭐⭐
ref 普通索引等值查询,可能多行 WHERE idx_col = 'value' ⭐⭐⭐⭐
fulltext 全文索引检索 MATCH() AGAINST() ⭐⭐⭐
ref_or_null ref + NULL 值比较 WHERE col = 1 OR col IS NULL ⭐⭐⭐
index_merge 使用多个索引取并集/交集 WHERE a=1 OR b=2 且 a、b 各有索引 ⭐⭐⭐
unique_subquery IN 子查询返回不重复值 WHERE id IN (SELECT pk FROM t2) ⭐⭐⭐
index_subquery IN 子查询可能返回重复值 WHERE id IN (SELECT col FROM t2) ⭐⭐
range 索引范围扫描 WHERE id BETWEEN 1 AND 10、>、<、IN、LIKE 'prefix%' ⭐⭐
index 全索引扫描 遍历整个索引树,不回表
ALL 🔴 全表扫描 未使用任何索引 ⭐(必须优化!)

🎯 优化目标:至少达到 range 级别,最好达到 ref 或 const,坚决杜绝 ALL

📐 key_len 计算规则

数据类型 占用字节
TINYINT 1
SMALLINT 2
MEDIUMINT 3
INT 4
BIGINT 8
FLOAT/DOUBLE 4/8
DATE 3
TIMESTAMP 4
DATETIME 8
CHAR(n) UTF8 3n
VARCHAR(n) UTF8 3n + 2(长度前缀)+ 1(NULL标识,如可为NULL)
CHAR(n) UTF8MB4 4n
VARCHAR(n) UTF8MB4 4n + 2 + 1(可为NULL时)

示例:VARCHAR(100) UTF8 可为NULL → 100 × 3 + 2 + 1 = 303 字节

💡 key_len 越短说明联合索引用的列越少,可判断索引是否生效

三、Extra 额外信息(⭐ 性能"晴雨表")

含义 优化建议
✅ Using index 覆盖索引,无需回表 理想状态,保持!
⚠️ Using where WHERE 过滤 正常场景,无需特别优化
🔴 Using filesort 无法用索引排序,需额外排序(内存/磁盘) 给 ORDER BY 列加索引
🔴 Using temporary 使用临时表(GROUP BY / DISTINCT 等) 给分组/去重列加索引
✅ Using index condition 索引条件下推(ICP,MySQL 5.6+) 优化特性,无需处理
⚠️ Using join buffer 使用连接缓冲区(BNL/BKA) 给 JOIN 条件加索引
🟢 Select tables optimized away 聚合函数通过索引直接返回 如 SELECT MAX(id) FROM t
🔴 Impossible WHERE WHERE 条件恒假 检查业务逻辑
🔴 Range checked for each record 逐行检查索引,极差 必须加索引

四、实战分析示例

EXPLAIN SELECT u.name, o.order_id
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.age > 18
ORDER BY u.create_time DESC
LIMIT 10;
问题 EXPLAIN 特征 优化方案
全表扫描 type=ALL, key=NULL 为 age 字段加索引
排序未用索引 Extra=Using filesort 为 create_time 加索引
未用覆盖索引 无 Using index 建复合索引 (age, create_time, name)
临时表 Extra=Using temporary 优化 GROUP BY 或用覆盖索引

五、一句话总结优先级

看 type(至少 range) → 看 key(不能 NULL)→ 看 rows(越小越好)
→ 看 Extra(消除 filesort/temporary,追求 Using index)

觉得上面的内容有用吗?快来点个赞吧!

点赞() 我要打赏

温馨提示 : 本站内容来自会员投稿以及互联网,所有源码及教程均为作者总结编辑,请大家在使用过程中提前做好备份,以免发生无法预知的错误,源码类教程请勿直接用于生产环境!

 可能感兴趣的文章