【MySQL】EXPLAIN 关键字详解
是用于分析 SQL 查询的执行计划。它能揭示 MySQL 如何执行查询(如是否使用索引、表连接顺序等),帮助我们定位性能瓶颈。基本用法输出列id - 查询标识符说明:① 标识 SELECT 所属的查询块② 相同 id 表示同一查询级别,执行顺序从上到下③ 不同 id 时,值越大优先级越高(越先执行)典型值:① 单查询:1② 嵌套查询:1(主查询),2(子查询)③ UNION:NULL(UNION
【MySQL】EXPLAIN 关键字详解
EXPLAIN
是用于分析 SQL 查询的执行计划。它能揭示 MySQL 如何执行查询(如是否使用索引、表连接顺序等),帮助我们定位性能瓶颈。
基本用法
EXPLAIN SELECT * FROM users WHERE age > 25;
输出列
列名 | 说明 | 关键值示例 |
---|---|---|
id | 查询标识符(相同 id 表示同组查询,执行顺序从上到下;不同 id 值越大优先级越高) | 1 (主查询)、2 (子查询) |
select_type | 查询类型 | SIMPLE (无子查询)、PRIMARY (外层查询)、SUBQUERY (子查询) |
table | 访问的表名 | users 、<derived2> (派生表)、<union1,2> (UNION 结果) |
partitions | 匹配的分区 | p0,p1 (分区表使用) |
type ⭐ | 访问类型(性能核心指标,从优到劣排序) | 重点顺序:system > const > eq_ref > ref > range > index > ALL |
possible_keys | 可能使用的索引 | idx_age (显示可选的索引名) |
key ⭐ | 实际使用的索引 | idx_email (若为 NULL 表示未用索引) |
key_len | 索引使用的字节数 | 4 (int 索引)、152 (varchar(50)) |
ref | 索引匹配的列或常量 | const (常量)、db1.users.id (其他表的列) |
rows ⭐ | 预估扫描行数(越小越好) | 10 (理想)、10000 (需优化) |
filtered | 存储引擎返回数据后在 server 层过滤的比例 | 100.0 (完全匹配)、10.0 (仅 10% 数据有效) |
Extra ⭐ | 额外执行信息(重要优化线索) | Using index 、Using temporary 、Using filesort (需警惕) |
-
id - 查询标识符
-
说明:
① 标识 SELECT 所属的查询块
② 相同 id 表示同一查询级别,执行顺序从上到下
③ 不同 id 时,值越大优先级越高(越先执行)
-
典型值:
① 单查询:1
② 嵌套查询:1(主查询),2(子查询)
③ UNION:NULL(UNION 结果集)
-
-
select_type - 查询类型
值 描述 示例场景 SIMPLE 简单 SELECT(无子查询/UNION) SELECT * FROM users
PRIMARY 最外层查询 包含子查询时的外层查询 SUBQUERY SELECT 中的子查询 SELECT id, (SELECT name FROM profiles) FROM users
DERIVED FROM 子句中的子查询 SELECT * FROM (SELECT * FROM orders) tmp
UNION UNION 中的第二个或后续 SELECT SELECT a FROM t1 UNION SELECT b FROM t2
UNION RESULT UNION 结果 UNION
操作的结果集DEPENDENT SUBQUERY 依赖外部查询的子查询 子查询依赖外层查询结果 MATERIALIZED 物化子查询(MySQL 5.6+) 子查询结果被物化为临时表 -
table - 访问的表
-
说明:
① 显示表名或别名
② 特殊格式:
(1) <derivedN>:
id=N 的派生表(2) <unionM,N>:
id=M 和 N UNION 的结果(3) <subqueryN>
:物化子查询 -
-
partitions - 匹配的分区
-
说明:
① 对于分区表,显示查询访问的分区
② 非分区表始终为 NULL -
示例:
p0,p1
(访问分区 p0 和 p1)
-
-
type ⭐(关键性能指标)- 访问类型
说明: 按性能从优到劣
排序类型 描述 性能 示例 system 系统表,仅一行 最优 MyISAM
引擎的空表const 主键/唯一索引的常量查询 极优 WHERE id = 1
eq_ref JOIN 时主键/唯一索引关联 优 JOIN ... ON t1.pk = t2.pk
ref 非唯一索引的等值查询 良 WHERE index_col = 10
fulltext 全文索引 中 MATCH(...) AGAINST(...)
ref_or_null ref + NULL 值搜索 中 WHERE col = 10 OR col IS NULL
index_merge 索引合并优化 中 多个索引条件组合 unique_subquery 唯一索引子查询 中 value IN (SELECT pk FROM ...)
index_subquery 非唯一索引子查询 中下 value IN (SELECT index_col FROM ...)
range 索引范围扫描 中下 WHERE id > 10
index 全索引扫描 差 SELECT indexed_col FROM table
ALL 全表扫描 最差 无索引查询 -
possible_keys - 可能使用的索引
-
说明:
① 查询可能选择的索引列表
② NULL 表示无可用索引
③ 实际使用的索引可能在 key 列不同
-
-
key ⭐ - 实际使用的索引
-
说明:
① 查询优化器最终选择的索引
② NULL 表示未使用索引
③ 可能不在 possible_keys 中(优化器选择更优索引)
-
-
key_len - 使用索引的长度(字节)
-
计算规则:
① 数值类型:
(1) TINYINT:1 字节 (2) INT:4 字节 (3) BIGINT:8 字节
② 字符串类型(UTF8mb4):
(1) CHAR(10):4×10 = 40 字节 (2) VARCHAR(10):4×10 + 长度字节(2字节)
③ NULL 标志:1 字节(若列可为 NULL)
-
示例:
①
int NOT NULL
:4②
varchar(255) NULL
:255×4 + 2 + 1 = 1023
-
-
ref - 索引比较的列或常量
-
格式:
①const
:常量值
②func
:函数结果
③db.table.column
:关联表的列 -
示例:
①
WHERE col = 10
→const
②JOIN ... ON t1.id
=t2.user_id → db.t2.user_id
-
-
rows ⭐ - 预估扫描行数
- 说明:
① 存储引擎层面预估的检查行数
② 重要性能指标(值越小越好)
③ 非精确值,基于统计信息估算
-
filtered - 存储引擎返回数据的过滤百分比
-
说明:
① MySQL 5.7+ 新增列
② 表示条件过滤后剩余数据的百分比
③ 计算最终行数:rows × filtered% -
示例:
① rows=1000, filtered=10.00 → 最终约 100 行
-
-
Extra ⭐(重要优化线索)- 附加执行信息
关键值详解:值 含义 优化建议 Using index 覆盖索引(无需回表) 优,保持 Using where Server 层过滤数据 检查索引使用 Using temporary 使用临时表 优化 GROUP BY/ORDER BY Using filesort 额外排序操作 为排序字段加索引 Select tables optimized away 使用聚合函数优化 优 Using index condition 索引条件下推(ICP) MySQL 5.6+ 优化特性 Using join buffer 使用连接缓冲区 增大 join_buffer_size Impossible WHERE WHERE 条件永不成立 查询逻辑错误 Distinct 优化 DISTINCT 操作 -
优化简单总结:
- 优先优化 type 列: 避免 ALL 和 index;
- 检查索引使用: key 不为 NULL,且 key_len 合理;
- 关注扫描行数: rows 值应尽可能小;
- 警惕额外操作: Using filesort 和 Using temporary 需优化;
- 善用覆盖索引: Using index 是最佳状态之一。
你可能发现你使用 EXPLAIN
后,输出的列只有 10 列或者 11 列,那是因为MySQL版本的缘故。小于 5.7 的版本,只会有 10 列输出。版本越高,优化升级会越多,能让我们更准确地判断索引选择和过滤效率。
更多推荐
所有评论(0)