MySQL EXPLAIN 怎么看
EXPLAIN 输出主要看这几个关键字段,我按重要性和常见坑点来讲。
核心字段速览
| 字段 | 含义 |
|---|---|
id |
查询的执行顺序标识,id 越大越先执行(子查询、派生表会有不同 id) |
select_type |
查询类型:SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION 等 |
table |
当前这一行对应的表 |
type |
最重要,访问类型,反映查询效率 |
possible_keys |
可能用到的索引 |
key |
实际用到的索引 |
key_len |
索引使用的字节数,可以判断联合索引用了几列 |
rows |
预估扫描行数(估算值,非精确) |
filtered |
按条件过滤后剩余行的百分比 |
Extra |
第二重要,很多关键信息都在这里 |
type 字段:从好到差的排序
system > const > eq_ref > ref > range > index > ALL
- system/const:主键或唯一索引等值查询,最快,基本只在单表单行时出现
- eq_ref:多表连接时,被驱动表用主键/唯一索引做等值匹配(比如
a.id = b.a_id且 b.a_id 是唯一索引) - ref:普通索引的等值查询,可能返回多行
- range:索引范围扫描,比如
>、<、BETWEEN、IN - index:索引全扫描(遍历整棵索引树),比 ALL 好但依然要扫全部索引
- ALL:全表扫描,一般需要优化
经验标准:一般要求至少达到 range 级别,最好是 ref 或以上,看到大表出现 ALL 基本就要警觉了。
Extra 字段:常见情况解读
1. Using filesort(需要额外排序)
出现在 ORDER BY 无法利用索引顺序时,MySQL 需要在内存或磁盘中额外排序。
常见诱因: - ORDER BY 的列没有索引 - 联合索引使用顺序和 ORDER BY 不一致 - WHERE 条件用了索引,但排序列不在索引里,且中间断了顺序性
优化思路:建立能同时覆盖 WHERE 和 ORDER BY 的联合索引,让索引顺序和排序顺序一致。
2. Using temporary(使用临时表)
常见于 GROUP BY、DISTINCT、某些子查询、UNION 场景。临时表开销较大,配合 Using filesort 出现时通常是性能瓶颈信号。
优化思路:GROUP BY 的列尽量走索引;避免不必要的 DISTINCT。
3. Using index(覆盖索引,好事)
表示查询所需的所有列都能从索引中直接获取,不需要回表查聚簇索引数据,效率很高。
这个和 Using where 不冲突,可能同时出现:"Using where; Using index" 表示用索引过滤又直接用索引取数据。
4. Using where
表示在存储引擎返回数据后,MySQL Server 层还需要根据 WHERE 条件再过滤一次(说明索引没有完全覆盖过滤条件)。单独出现不算坏事,但结合 type=ALL 就意味着全表扫描后再过滤,效率差。
5. Using index condition(索引下推 ICP)
5.6+ 版本引入,将部分 WHERE 条件下推到存储引擎层用索引过滤,减少回表次数,属于优化效果,是好事。
6. Using join buffer
两表连接时,被驱动表没有可用索引,MySQL 用连接缓冲区(Block Nested Loop)来减少扫描次数。出现这个通常意味着被驱动表缺少合适的索引,需要加索引。
7. Impossible WHERE / const row not found
说明 WHERE 条件本身就不可能成立(比如逻辑矛盾),或者表是空表,MySQL 直接判断不需要真正查询。
联合索引相关的常见坑
最左前缀失效
联合索引 (a, b, c):
- WHERE a=1 AND b=2 → 能用索引
- WHERE b=2 AND c=3(跳过 a)→ 用不上这个索引
- WHERE a=1 AND c=3(跳过 b)→ 只能用到 a 这一列
key_len 判断实际用了几列
比如 key_len=5,如果第一列是 int(4字节)+1字节null标记,说明只用了联合索引的第一列,第二列没用上——这时候要回头看 WHERE 条件写法或者数据类型是否匹配。
索引失效的典型场景
- 索引列上做了函数运算:
WHERE YEAR(create_time)='2024'→ 索引失效 - 隐式类型转换:字段是 varchar,但传入的是数字,MySQL 会做类型转换导致索引失效
LIKE '%xxx'前导通配符 → 索引失效(LIKE 'xxx%'可以用)- 索引列参与了运算:
WHERE id + 1 = 100 OR条件中有一侧列没有索引,可能导致整体索引失效(视版本和优化器而定)- 联合索引里,中间某列用了范围查询(如
>),后面的列即使在索引里也不能再用来等值过滤索引(只能用于排序覆盖等有限场景)
一个简单排查思路
- 先看
type,是不是 ALL/index 这种低效访问 - 看
key是不是空,如果possible_keys有值但key是 NULL,说明优化器没选它(可能被判断为不划算,或者其实是索引失效) - 看
rows,扫描行数和实际结果差异大不大 - 看
Extra,重点关注Using filesort和Using temporary - 用
key_len验证联合索引到底用了几列