目录
[一、EXPLAIN 核心概述](#一、EXPLAIN 核心概述)
[1.1 定义与作用](#1.1 定义与作用)
[1.2 适用范围](#1.2 适用范围)
[1.3 输出格式](#1.3 输出格式)
[二、EXPLAIN 输出字段全解析](#二、EXPLAIN 输出字段全解析)
[2.1 核心字段总览](#2.1 核心字段总览)
[2.2 字段详细说明(附实战案例)](#2.2 字段详细说明(附实战案例))
[2.2.1 id:查询执行顺序标识](#2.2.1 id:查询执行顺序标识)
[2.2.2 select_type:查询类型](#2.2.2 select_type:查询类型)
[2.2.3 table:表 / 临时表标识](#2.2.3 table:表 / 临时表标识)
[2.2.4 type:访问类型(核心指标)](#2.2.4 type:访问类型(核心指标))
[2.2.5 possible_keys & key:索引选择](#2.2.5 possible_keys & key:索引选择)
[2.2.6 key_len:索引长度(字节)](#2.2.6 key_len:索引长度(字节))
[2.2.7 ref:匹配对象](#2.2.7 ref:匹配对象)
[2.2.8 rows:预估扫描行数](#2.2.8 rows:预估扫描行数)
[2.2.9 filtered:过滤比例](#2.2.9 filtered:过滤比例)
[2.2.10 Extra:额外关键信息(性能陷阱)](#2.2.10 Extra:额外关键信息(性能陷阱))
[✅ 优质信号(无需优化)](#✅ 优质信号(无需优化))
[3.1 案例 1:主键查询(最优性能)](#3.1 案例 1:主键查询(最优性能))
[3.2 案例 2:全表扫描(需优化)](#3.2 案例 2:全表扫描(需优化))
[3.3 案例 3:覆盖索引(最优优化)](#3.3 案例 3:覆盖索引(最优优化))
[3.4 案例 4:文件排序(需优化)](#3.4 案例 4:文件排序(需优化))
[四、EXPLAIN 进阶用法](#四、EXPLAIN 进阶用法)
[4.1 格式化输出](#4.1 格式化输出)
[4.2 分析实际执行情况](#4.2 分析实际执行情况)
[4.3 分区表分析](#4.3 分区表分析)
[5.1 核心优化原则](#5.1 核心优化原则)
[5.2 调优流程](#5.2 调优流程)
一、EXPLAIN 核心概述
1.1 定义与作用
EXPLAIN 是 MySQL 提供的 SQL 性能分析工具,用于模拟优化器执行 SQL 语句,展示查询执行计划(Execution Plan),核心作用包括:
- 揭示 MySQL 如何选择索引 、联表顺序 、扫描行数;
- 定位慢 SQL 瓶颈(如全表扫描、临时表、文件排序);
- 指导索引优化与 SQL 改写,是数据库调优的必备工具。
1.2 适用范围
支持 SELECT、DELETE、INSERT、REPLACE、UPDATE 语句,不真实执行 SQL,仅输出优化器的执行策略。
1.3 输出格式
默认输出为传统表格格式 ,也可通过 FORMAT=JSON/FORMAT=TREE 查看结构化 / 树形结构,便于复杂查询分析。
二、EXPLAIN 输出字段全解析
2.1 核心字段总览
| 字段名 | 核心含义 | 重要等级 |
|---|---|---|
| id | 查询执行顺序标识 | ★★★★ |
| select_type | 查询类型(简单 / 子查询 / 联合) | ★★★★ |
| table | 涉及的表 / 临时表 | ★★★ |
| type | 访问类型(索引使用效率核心) | ★★★★★ |
| possible_keys | 可选索引列表 | ★★★ |
| key | 实际使用的索引 | ★★★★★ |
| key_len | 实际使用的索引长度(字节) | ★★★★ |
| ref | 与索引匹配的列 / 常量 | ★★★ |
| rows | 预估扫描行数 | ★★★★ |
| filtered | 过滤后剩余数据比例 | ★★★ |
| Extra | 额外关键信息(性能陷阱) | ★★★★★ |
2.2 字段详细说明(附实战案例)
2.2.1 id:查询执行顺序标识
-
含义 :查询中每个
SELECT子句的唯一编号,决定执行优先级。 -
规则 :
- 数值越大 ,执行越先(子查询 / 派生表优先执行);
- 数值相同 ,按从上到下顺序执行;
- 为
NULL:表示该行为联合查询结果(如<union M,N>),需合并 id 为 M、N 的结果。
-
示例 :
sql-- 子查询+联合查询示例 EXPLAIN SELECT * FROM t1 WHERE id = 1 UNION SELECT * FROM t2 WHERE id IN (SELECT id FROM t3);执行顺序:id=3(子查询)→ id=2(t2 查询)→ id=1(t1 查询)→ 合并 union 结果。
2.2.2 select_type:查询类型
| 取值 | 含义 | 性能提示 |
|---|---|---|
| SIMPLE | 简单查询(无 子查询 / UNION) | ✅ 基础查询,性能稳定 |
| PRIMARY | 最外层查询(含子查询 / UNION 时) | - |
| SUBQUERY | 子查询中的第一个 SELECT(非相关子查询) | ⚠️ 可能存在性能损耗,建议优化为 JOIN |
| DERIVED | 派生表(FROM 子句中的子查询) | ⚠️ 会生成临时表,大数据量下性能差 |
| UNION | UNION 中第二个及后续的 SELECT | ⚠️ 需合并结果,额外开销 |
| UNION RESULT | UNION 合并后的结果集 | 无实际表,table 列显示 <union M,N> |
| DEPENDENT SUBQUERY | 相关子查询(依赖外层查询结果) | ❌ 性能极差,优先改写为 JOIN |
| MATERIALIZED | 子查询结果物化(生成临时表) | ✅ 优化相关子查询的替代方案 |
2.2.3 table:表 / 临时表标识
- 显示当前行对应的表名 或别名;
- 特殊值:
<derivedN>:id 为 N 的派生表;<subqueryN>:id 为 N 的物化子查询结果;<union M,N>:合并 id 为 M、N 的 UNION 结果。
2.2.4 type:访问类型(核心指标)
决定索引使用效率的最关键字段 ,性能从优到差排序如下,需尽量达到 range 及以上级别:
| 取值 | 含义 | 适用场景 | 性能等级 |
|---|---|---|---|
| system | 表中仅有 1 行数据 | 系统表 | 最优 |
| const | 主键 / 唯一索引等值查询,最多匹配 1 行 | WHERE id=1(id 为主键) |
极优 |
| eq_ref | 联表时,被驱动表用主键 / 唯一索引等值匹配 | 联查询(JOIN ... ON 主键列) |
极优 |
| ref | 普通索引等值查询,可匹配多行 | WHERE name='张三'(name 建索引) |
优 |
| range | 索引范围查询(>、<、BETWEEN、IN) | WHERE id BETWEEN 1 AND 100 |
良 |
| index | 全索引扫描(遍历整个索引树) | 需覆盖索引,但无过滤条件 | 差 |
| ALL | 全表扫描(遍历所有数据行) | 无索引 / 小表临时查询 | 最差(大表禁用) |
2.2.5 possible_keys & key:索引选择
- possible_keys :MySQL 评估的可选索引列表,仅为参考,不代表实际使用;
- key :MySQL 实际选用 的索引,为
NULL则表示未使用索引(需优化)。 - 关键判断 :
- 若
possible_keys非空但key为空,说明索引未命中,需检查索引设计 / SQL 写法; - 联合索引需遵循最左匹配原则,否则索引失效。
- 若
2.2.6 key_len:索引长度(字节)
- 表示 MySQL 实际使用的索引长度 ,越短越好;
- 核心用途:判断联合索引用到了几列。
- 常见数据类型长度参考(utf8mb4 编码):
| 数据类型 | 长度(字节) |
|---|---|
| INT | 4 |
| BIGINT | 8 |
| VARCHAR(100) | 100×4 + 2 = 402 |
| DATETIME | 5(5.6+ 版本)/ 8(旧版本) |
| CHAR(10) | 10×4 = 40 |
- 示例 :联合索引
idx_a_b_c (a INT, b VARCHAR(10), c INT)key_len=4:仅使用第 1 列(a);key_len=406:使用第 1、2 列(a + b);key_len=410:使用全部 3 列。
2.2.7 ref:匹配对象
- 表示与索引列等值匹配 的对象,可为:
- 常量(如
'张三'、1); - 其他表的列(如
db.t2.id); NULL:非等值匹配或无匹配。
- 常量(如
2.2.8 rows:预估扫描行数
- MySQL 基于统计信息估算 的需扫描行数,数值越小越好;
- 与实际行数可能存在偏差,可通过
ANALYZE TABLE更新统计信息; - 优化目标:大表场景下,尽量将 rows 控制在可接受范围(如万级以内)。
2.2.9 filtered:过滤比例
- 表示存储引擎返回数据后,经
WHERE条件过滤后剩余的比例(%); - 数值越高 ,说明索引筛选能力越强,查询效率越高;
- 示例:
rows=1000,filtered=10%→ 预估最终返回 100 行。
2.2.10 Extra:额外关键信息(性能陷阱)
最易被忽略但最关键的字段,直接暴露 SQL 性能问题,常见取值如下:
✅ 优质信号(无需优化)
| 取值 | 含义 |
|---|---|
| Using index | 覆盖索引(索引包含查询所需所有字段,无需回表),性能最优 |
| Using where | 已通过 WHERE 条件过滤数据 |
⚠️ 优化信号(需关注)
| 取值 | 含义 | 优化建议 |
|---|---|---|
| Using index condition | 索引条件下推(ICP),减少回表 | 检查联合索引列顺序,提升筛选效率 |
| Using temporary | 生成临时表(常见于 GROUP BY/UNION/DISTINCT) | 优化分组 / 排序逻辑,添加合适索引 |
| Using filesort | 文件排序(未使用索引排序) | 为排序字段建索引,避免全表排序 |
❌ 危险信号(必须优化)
| 取值 | 含义 | 优化建议 |
|---|---|---|
| Impossible WHERE | WHERE 条件永远为假 | 检查 SQL 逻辑,删除无效查询 |
| Select tables optimized away | 无需访问表(如聚合函数查询) | 无需处理(性能最优) |
三、实战案例分析
3.1 案例 1:主键查询(最优性能)
sql
EXPLAIN SELECT * FROM user WHERE id = 1;
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | user | const | PRIMARY | 1 | NULL |
- 分析:type=const(主键等值查询),key=PRIMARY,rows=1,性能最优。
3.2 案例 2:全表扫描(需优化)
sql
EXPLAIN SELECT * FROM user WHERE name = '张三';
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | user | ALL | NULL | 1000 | Using where |
- 分析 :type=ALL(全表扫描),key=NULL,需为
name字段创建索引。
3.3 案例 3:覆盖索引(最优优化)
sql
-- 先创建索引:CREATE INDEX idx_name_age ON user(name, age);
EXPLAIN SELECT name, age FROM user WHERE name = '张三';
| id | select_type | table | type | key | Extra |
|---|---|---|---|---|---|
| 1 | SIMPLE | user | ref | idx_name_age | Using index |
- 分析:Extra=Using index(覆盖索引),无需回表,性能最优。
3.4 案例 4:文件排序(需优化)
| id | select_type | table | type | Extra |
|---|---|---|---|---|
| 1 | SIMPLE | user | ALL | Using filesort |
- 分析 :Extra=Using filesort,需为
create_time建索引,避免全表排序。
四、EXPLAIN 进阶用法
4.1 格式化输出
sql
-- JSON 格式(适合复杂查询)
EXPLAIN FORMAT=JSON SELECT * FROM user WHERE id=1;
-- 树形格式(直观展示执行顺序)
EXPLAIN FORMAT=TREE SELECT * FROM user u JOIN order o ON u.id=o.user_id;
4.2 分析实际执行情况
EXPLAIN ANALYZE 会真实执行 SQL,并输出实际执行时间、扫描行数,对比预估与实际值的偏差:
sql
EXPLAIN ANALYZE SELECT * FROM user WHERE name='张三';
4.3 分区表分析
添加 PARTITIONS 关键字,显示命中的分区信息:
sql
EXPLAIN PARTITIONS SELECT * FROM user_part WHERE id=1;
五、总结与优化原则
5.1 核心优化原则
- type 达标 :尽量达到
range及以上,避免ALL; - 索引命中 :保证
key非空,遵循联合索引最左匹配原则; - 减少回表:优先使用覆盖索引(Using index);
- 消除额外开销 :避免
Using temporary、Using filesort。
5.2 调优流程
- 用
EXPLAIN分析慢 SQL; - 重点关注
type、key、Extra字段; - 针对性优化(建索引、改写 SQL、调整表结构);
- 再次用
EXPLAIN验证优化效果。
EXPLAIN是 MySQL 调优的入门钥匙,掌握其核心字段含义,能快速定位 SQL 性能瓶颈。在实际开发中,需结合业务场景灵活运用,避免过度优化。