SQL执行计划
MySQL Explain执行计划 核心知识点
一、基础概述
1. 作用
EXPLAIN 用于模拟MySQL执行SQL,输出查询执行计划,分析索引使用、扫描方式、性能瓶颈,是慢SQL优化的核心工具。
2. 核心区别
-
EXPLAIN:仅预估执行计划,不真实执行SQL,无耗时、无IO开销
-
EXPLAIN ANALYZE(MySQL8.0.18+):真实执行SQL,输出预估+真实耗时、扫描行数、循环次数
-
⚠️ 线上使用
EXPLAIN ANALYZE需谨慎,大SQL会真实执行并可能压垮数据库;轻量级SQL可酌情使用
3. 执行顺序规则
-
id值越大,越优先执行
-
id值相同,从上到下顺序执行
-
id为NULL:UNION合并结果集
二、Explain 10大字段详解(核心)
1. id 执行序号
标识当前行在查询中的执行顺序,是判断子查询、UNION、JOIN执行优先级的核心依据。
- id值越大,越优先执行
- id相同,从上到下顺序执行
- id为NULL,表示该行为结果集(如UNION RESULT)
2. table 表名
标识当前行访问的是哪张表。
- 普通表名:直接访问的物理表
<derivedN>:派生表(FROM子查询生成的临时表),N为对应的id<unionM,N>:UNION合并结果集<subqueryN>:物化子查询
3. select_type 查询类型
标识当前查询块的类型,高频知识点:
-
SIMPLE:简单查询,无子查询、无UNION
-
PRIMARY:最外层主查询
-
SUBQUERY:普通子查询,独立执行
-
DEPENDENT SUBQUERY:高危!相关子查询,外层每一行执行一次子查询,性能极差
-
DERIVED:派生表(FROM后嵌套子查询),会生成临时表
-
UNION:UNION中第二个及后续查询
-
UNION RESULT:UNION结果合并,id为NULL
4. type 访问类型(最重要指标)
SQL查询性能核心标尺,性能从优到劣排序:
system > const > eq_ref > ref > ref_or_null > range > index_merge > index > ALL
-
system/const:最优,主键/唯一索引常量匹配,仅1行数据
-
eq_ref:JOIN查询主键/唯一索引匹配,每行唯一匹配
-
ref:普通二级索引等值查询,常规最优业务状态
-
ref_or_null:索引等值查询+NULL值匹配
-
range:范围查询(>、<、BETWEEN、IN),走索引范围扫描
-
index_merge:索引合并,多个单列索引合并结果,性能弱于联合索引
-
index:索引全扫描,遍历整棵索引树,大表性能差
-
ALL:最差,全表扫描,大表绝对禁止
✅ 优化目标:业务SQL尽量保证 ref/range,杜绝大表 index/ALL
5. possible_keys / key / ref
-
possible_keys:理论上可以使用的索引
-
key:实际最终使用的索引(NULL代表未走索引)
-
ref:显示哪些列或常量被用于和索引进行比较(如 const、字段名等)
高频问题:possible_keys有值、key为NULL的5大原因
-
索引失效:索引列函数运算、隐式类型转换、LIKE前缀通配、OR条件失效
-
数据占比过高:满足条件数据占比较大(经验参考约30%,实际阈值受表大小、Buffer Pool、数据分布等因素影响),优化器认为全表扫描代价更低
-
统计信息失真:大批量增删改后,采样数据不准,优化器误判
-
索引选择性极差:如status状态字段,区分度极低
-
SQL强制忽略索引:
ignore index
6. key_len 索引长度
作用:判断联合索引最左前缀使用到第几列,仅统计索引条件字段,与SELECT字段无关。
utf8mb4 计算规则:
- int:4字节;not null无额外开销,null+1字节
- bigint:8字节;not null无额外开销,null+1字节
- char(n):n*4字节;not null无额外开销,null+1字节
- varchar(n):n*4 + 2(2字节长度开销),null+1字节
- date:3字节;datetime:5字节(MySQL 5.6+);timestamp:4字节
- 所有类型:可为NULL字段额外+1字节
7. rows
优化器预估扫描行数,非真实行数,数值越大性能越差。
失真原因:统计信息采样偏差、数据倾斜、大批量数据变更未更新统计。
修复命令:analyze table 表名;
8. filtered 过滤比例
表示经过WHERE条件过滤后,预估剩余行数的百分比(1-100)。
- 值越接近100,说明过滤效率越高,扫描的行数大部分都满足条件
- 值很低时,说明大量行被过滤掉,可能需要优化索引或SQL写法
9. Extra 额外信息(坑点最多)
✅ 优质标记
-
Using index:覆盖索引,无需回表,性能最优
-
Using index condition(ICP):索引条件下推,存储引擎层过滤数据,减少回表
❌ 高危慢SQL标记
-
Using filesort:文件排序,未利用索引有序性,需额外排序
-
Using temporary:创建临时表,常见于GROUP BY、DISTINCT、UNION
-
Using join buffer:JOIN无索引,走块嵌套循环或Hash Join,性能差
⚠️ 易错标记
- Using where:不代表索引失效!仅表示MySQL服务层二次过滤数据。只有
type=ALL+Using where才是全表扫描低效。
三、执行计划进阶核心知识点
1. ICP 索引条件下推
MySQL5.6+默认开启,核心作用:减少回表次数
原理:将索引列的WHERE过滤条件,下推到InnoDB存储引擎层执行,提前过滤无效数据,避免所有匹配索引前缀的数据都回表查询。
2. 索引合并 index_merge
原理:没有合适联合索引,MySQL 就帮你把多个单列索引拼起来用
结论:出现 index_merge 通常意味着索引设计不合理,缺少合适的联合索引
场景:单条SQL使用多个单列索引,合并结果集(常见OR查询)。
缺点:多次索引扫描、额外合并去重开销大、无法利用索引有序性、性能远不如联合索引。应优先建立联合索引,而非依赖索引合并。
3. Hash Join 特性(MySQL8.0+)
无索引大表JOIN替代块嵌套循环,性能大幅提升。
说明:普通EXPLAIN的Extra列会显示Hash Join标记(如Using join buffer (hash join)),可识别算法类型;EXPLAIN ANALYZE在此基础上额外提供真实耗时、实际行数等运行时统计信息。
4. 优化器重写规则
用户编写的SQL不等于实际执行SQL,优化器会自动改写:
-
IN子查询转JOIN
-
派生表合并(derived_merge)
-
OUTER JOIN转INNER JOIN
-
常量折叠、条件简化
查看真实执行SQL:EXPLAIN后执行 show warnings;
5. Explain 致命局限性(高频)
-
仅为预估计划,rows为估算值,统计信息不准会误导判断
-
无法识别锁、事务、死锁、长事务、IO并发问题(很多SQL计划完美,并发卡死)
-
对LIMIT截断优化效果体现有限(仅部分场景可通过Extra信息间接判断)
四、常见慢SQL执行计划特征+优化方案
| 慢SQL现象 | 执行计划特征 | 优化方案 |
|---|---|---|
| 全表扫描 | type=ALL、key=NULL、rows巨大 | 建立合适索引,修复索引失效写法,更新统计信息 |
| 排序慢 | Extra: Using filesort | 建立 WHERE+ORDER BY 联合索引,利用索引有序性 |
| 分组/去重慢 | Extra: Using temporary | 索引覆盖分组字段,拆分大SQL,减少DISTINCT |
| JOIN关联慢 | Extra: Using join buffer | 关联字段建索引,小表驱动大表,减少JOIN表数量 |
| 大量回表查询 | 无Using index,仅普通ref/range | 建立覆盖索引,禁止SELECT * |
五、重点知识点
1. Using where 代表索引失效吗?
不代表。Using where 是MySQL服务层二次过滤数据。只有同时满足 type=ALL + Using where 才是全表扫描、索引失效。正常走索引的SQL也会出现Using where,属于正常现象。
2. key_len 的作用和计算方式?
作用:判断联合索引最左前缀的使用列数。utf8mb4下int占4字节,bigint占8字节,char(n)占4n字节,varchar(n)占4n+2字节,可为NULL字段额外+1字节。
3. explain的rows为什么不准?怎么修复?
rows是优化器采样估算值,非真实行数。大批量增删改、数据倾斜会导致统计信息失真。执行 analyze table 表名 更新统计信息即可修复。
4. DEPENDENT SUBQUERY 有什么问题?
属于相关子查询,外层查询每遍历一行,子查询就执行一次,大表场景性能爆炸。新版本优化器会自动改写为JOIN,推荐手动改写JOIN替代子查询。
5. ICP索引条件下推的作用?
将索引列的过滤条件下推到存储引擎层,在索引内部提前过滤无效数据,大幅减少回表查询次数,提升查询性能。
6. explain和explain analyze的区别?线上能用吗?
explain仅预估计划、不执行SQL;explain analyze真实执行SQL,输出真实耗时和行数。线上对大SQL禁止使用,会真实执行并可能压垮数据库;轻量级SQL可酌情使用,仅测试环境使用为佳。
7. 索引合并和联合索引哪个好?
优先使用联合索引。索引合并是多个单列索引拼接结果,开销大、效率低,是优化器兜底方案,不如联合索引高效稳定。
8. explain能排查锁、死锁问题吗?
不能。explain仅分析SQL执行逻辑和索引使用,无法感知事务、锁等待、死锁、IO并发问题,并发性能问题需要通过 show engine innodb status 排查。
六、慢SQL标准分析流程(模板)
1. 从慢查询日志抓取慢SQL,确认耗时、扫描行数;
2. 使用EXPLAIN分析执行计划,通过id确认执行顺序;
3. 优先查看type,杜绝大表index/ALL全表扫描;
4. 核对key字段,确认索引是否生效,排查索引失效、优化器选错索引问题;
5. 通过key_len判断联合索引是否完全利用;
6. 查看rows预估扫描量和filtered过滤比例,判断数据扫描效率;
7. 重点排查Extra中的filesort、temporary、join buffer等高危标记;
8. 执行show warnings查看优化器重写后的真实SQL;
9. 结合锁、事务、统计信息排查隐性性能问题;
10. 优化索引、改写SQL后,重新explain验证效果。

浙公网安备 33010602011771号