引言
explain 是 mysql sql 优化神器,用来查看 mysql 执行计划,能清晰看到 mysql 如何执行你的查询、是否使用索引、表关联顺序、数据扫描行数等,是排查慢查询、优化 sql 的核心工具。
一、基础用法
1. 标准语法
-- 直接加在 select/delete/update/insert 语句前面 explain select * from user where id = 1; -- 查看更详细的执行计划(推荐使用) explain analyze select * from user where id = 1; -- mysql 8.0.18+ 支持
2. 能查什么?
- 表的读取顺序
- 表的读取类型(是否高效)
- 索引是否命中、命中哪个索引
- 扫描的数据行数
- 数据过滤比例
- 表之间的关联方式
二、执行计划字段全解
执行 explain 后会返回一张表,共 12+ 个关键字段,下面是最核心、必须掌握的字段:
1. id(查询执行顺序)
表示查询中执行 select 子句或操作表的顺序。
- id 相同:执行顺序从上到下
- id 不同:id 越大优先级越高,越先执行
- id 为 null:表示这是一个结果集,无需执行
2. select_type(查询类型)
判断查询是简单查询还是复杂查询:
| 值 | 含义 |
|---|---|
| simple | 简单查询(不包含子查询、union) |
| primary | 复杂查询中最外层的查询 |
| subquery | 子查询(select 里面嵌套的查询) |
| derived | 派生表(from 子句中的子查询) |
| union | union 中的第二个及后面的查询 |
| union result | union 的结果集 |
3. table(涉及的表)
显示这一行数据是关于哪张表的。
- 可能是表名
- 可能是别名
- 可能是
<derivedn>/<unionm,n>(临时表)
4. type(访问类型 → 核心!)
sql 优化最重要的指标,表示 mysql 在表中找到数据的方式,性能从好到坏排序:
system > const > eq_ref > ref > range > index > all
✅ 优化目标:至少达到 range,最好 ref 及以上
各类型详解
- system:表只有一行数据(系统表),极致性能
- const:通过主键 / 唯一索引精确匹配一行数据(如 where id=1)
- eq_ref:多表关联时,主键 / 唯一索引关联,每次只匹配一行
- ref:普通索引匹配,找到多个符合条件的行(最常见的优化目标)
- range:索引范围查询(>、<、between、in、like 前缀匹配)
- index:遍历整个索引树(比全表快,但仍需优化)
- all:全表扫描(最差!必须优化)
5. possible_keys(可能用到的索引)
mysql 认为可能会用于查询的索引,但最终不一定使用。
- 为 null:无可用索引
- 显示多个索引:mysql 会从中选最优的一个
6. key(实际使用的索引)
真正命中的索引,优化核心看这个字段!
- 为 null:没有使用索引(严重问题)
- 显示索引名:使用了该索引
7. key_len(使用的索引长度)→ 超详细计算规则
key_len 表示 mysql 实际使用的索引字节长度,用来判断:
- 联合索引用了几列
- 索引是否充分利用
- 字段是否允许 null、是否变长
计算核心公式
key_len = 字段实际字节数 + null标记(1字节) + 变长字段长度(2字节)
一、基础数据类型字节数
先记住常用字段固定字节:
| 字段类型 | 字节数 | 说明 |
|---|---|---|
| tinyint | 1 | -128~127 |
| smallint | 2 | 小整数 |
| int | 4 | 普通整数 |
| bigint | 8 | 长整数 |
| float | 4 | 单精度 |
| double | 8 | 双精度 |
| char(n) | n × 字符集字节 | 定长字符串 |
| varchar(n) | n × 字符集字节 | 变长字符串 |
| date | 3 | 日期 |
| datetime | 8 | 日期时间 |
| timestamp | 4 | 时间戳 |
字符集占用字节
- utf8:1 字符 = 3 字节
- utf8mb4:1 字符 = 4 字节
- gbk:1 字符 = 2 字节
- latin1:1 字符 = 1 字节
二、3 个额外规则(必记)
- 允许 null → +1 字节
字段定义default null,索引会多 1 字节标记 null。 - 变长字段(varchar/varbinary)→ +2 字节
用来存储字符串长度。 - 联合索引 → 多列累加计算
三、实战计算案例(一看就会)
案例 1:int 类型
age int not null -- 索引
key_len = 4(int)+ 0(not null)= 4
age int null -- 索引
key_len = 4 + 1(null)= 5
案例 2:char 固定字符串
name char(10) not null utf8mb4
key_len = 10×4 + 0 = 40
name char(10) null utf8mb4
key_len = 10×4 + 1 = 41
案例 3:varchar 变长字符串(最常用)
phone varchar(20) not null utf8mb4
key_len = 20×4 + 2(变长)= 82
phone varchar(20) null utf8mb4
key_len = 20×4 + 2 + 1 = 83
案例 4:联合索引(判断用了几列)
表结构:
idx_age_name(age int, name varchar(10)) age int not null name varchar(10) null utf8mb4
- 只用到 age:key_len = 4
- 用到 age + name:4 + (10×4 +2 +1) = 4+43=47
看到 key_len=47 → 说明联合索引两列都用上了!
四、快速计算速查表
| 字段定义 | key_len |
|---|---|
| int not null | 4 |
| int null | 5 |
| bigint not null | 8 |
| bigint null | 9 |
| varchar(20) not null utf8mb4 | 20×4+2=82 |
| varchar(20) null utf8mb4 | 20×4+2+1=83 |
| char(10) not null utf8 | 30 |
| char(10) null utf8 | 31 |
五、key_len 核心用途(优化必用)
- 判断联合索引是否用满
联合索引 idx(a,b,c)
key_len 小 → 只用了前面 1~2 列
key_len 大 → 全部列都命中 - 判断是否因为 null 浪费空间
- 判断索引是否精准命中
总结
- 固定类型:直接字节数
- 允许 null:+1
- 变长字段:+2
- 字符串:字符数 × 字符集字节
- 联合索引:多列累加
8. ref(与索引比较的列)
显示哪个列 / 常量和索引比较,找到匹配的数据。
示例:const(常量匹配)、库名.表名.列名
9. rows(扫描行数)
mysql 预估要扫描读取的数据行数。
- 数值越小越好
- 全表扫描时,这个值会非常大
10. extra(额外重要信息)
包含很多关键优化提示,重点关注:
| 值 | 含义 & 优化建议 |
|---|---|
| using index | ✅ 覆盖索引!查询的字段刚好在索引里,无需回表(最优) |
| using where | 使用 where 条件过滤数据 |
| using filesort | ❌ 文件排序!mysql 无法用索引排序,需额外排序(必须优化) |
| using temporary | ❌ 使用临时表!常见于 group by /order by(必须优化) |
| impossible where | where 条件永远不成立(无意义查询) |
三、实战案例:看懂执行计划
案例 1:主键查询(最优)
explain select * from user where id = 1;
结果:
- type: const
- key: primary
- extra: 无额外信息
✅ 完美,直接命中主键索引
案例 2:普通索引查询
explain select name from user where phone = '13800138000';
结果:
- type: ref
- key: idx_phone
- extra: using index
✅ 优秀,覆盖索引,无需回表
案例 3:全表扫描(最差)
explain select * from user where age = 20;
结果:
- type: all
- key: null
- rows: 10000
❌ 严重问题,全表扫描,必须给 age 加索引
案例 4:索引失效(文件排序)
explain select * from user order by address;
结果:
- extra: using filesort
❌ 必须给 address 加索引优化排序
四、索引失效常见场景(用 explain 快速判断)
执行计划中 key=null 就是索引失效,常见原因:
1. 索引列上使用函数 / 运算
-- 失效 select * from user where year(create_time) = 2024;
2. 模糊查询以 % 开头
-- 失效 select * from user where name like '%张三';
3. 类型隐式转换(字符串不加引号)
-- 失效(phone 是字符串,没加引号) select * from user where phone = 13800138000;
4. 使用 not in、!=、is not null 等
5. 联合索引不满足最左前缀原则
五、explain 使用总结(速记)
- 看 type:至少达到 range,优先 ref
- 看 key:必须有索引,不能为 null
- 看 rows:扫描行数越少越好
- 看 extra:严禁 using filesort、using temporary
- 加索引:全表扫描、索引失效时优先加合适索引
总结
explain 是 mysql 优化必用工具,核心看执行计划最重要指标:type(访问类型)、key(实际索引)、extra(额外信息)
优化目标:避免全表扫描、文件排序、临时表,尽量使用覆盖索引
8.0+ 推荐用 explain analyze,能看到实际执行时间,优化更精准
到此这篇关于mysql explain语法使用的文章就介绍到这了,更多相关mysql explain语法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论