EXPLAIN 用法详解(表格)
SQL 执行慢?慢在哪里?EXPLAIN
能做什么? —— 它可以预估执行计划,而不是执行 SQL 本身。EXPLAIN
的意义:了解优化器是怎么走表的
1、基础语法,EXPLAIN怎么写
EXPLAIN SELECT * FROM user WHERE id = 1;
EXPLAIN EXTENDED——
这是EXPLAIN
的加强版,除了给出基本的执行计划,还会显示优化器实际执行时是怎么改写你的 SQL 的。EXPLAIN FORMAT=JSON
——这个是EXPLAIN
的 JSON 格式输出,比传统表格输出更全面,信息更细节,适合程序自动解析或更细粒度分析。EXPLAIN ANALYZE
——这是 MySQL 8.0 的“加强版 EXPLAIN”,它会 真正执行语句,并且把真实执行的时间、行数、CPU 使用情况也一起打印出来。
2、重点列含义解析
列名 | 含义 | 常见值 | 典型用法 |
---|---|---|---|
id | 查询中执行步骤的序号 | 数字,越大越先执行 | id 大优先 |
select_type | 查询类型 | SIMPLE, PRIMARY, SUBQUERY | 是否子查询、派生表 |
table | 当前访问的表 | 表名或派生表别名 | 哪个表 |
partitions | 分区信息 | NULL 或分区名 | 用于分区表 |
type | 连接类型 | ALL, index, range, ref, eq_ref | 越往下性能越好 |
possible_keys | 可能用到的索引 | 索引名 | 这里有索引未必用 |
key | 实际使用的索引 | 索引名 | 用了哪个索引 |
key_len | 使用的索引长度 | 字节数 | 判断是否用上了组合索引 |
ref | 哪个列或常数用于索引查找 | 列名、const | 用什么条件去匹配索引 |
rows | 预估扫描行数 | 数字 | 越少越好 |
filtered | 过滤后留下的百分比 | 百分数 | 新版本有 |
Extra | 额外信息 | Using filesort, Using temporary | 关键要看有没有可优化的操作 |
3、常见的Extra信息解读:
- Using index
- 表示这条查询只用到了索引中的数据,不需要回表去取原表里的行。也叫 覆盖索引扫描(Covering Index Scan)。一般是因为
SELECT
的列都包含在索引里。 - 实质:只从索引就能拿到需要的列,省掉了去表里再查一趟,I/O 更少,性能好。
- Using where
- 表示即使用了索引,也需要再做一次 WHERE 条件过滤,因为索引只定位到了范围,还要额外检查行是否满足条件。
SELECT * FROM user WHERE age > 20;
- 如果
age
有索引,那么先用索引定位范围,但大于号范围可能会多扫一些数据,需要后面再筛一遍。
- Using filesort
- 表示查询结果需要做 额外排序,而不是直接用索引顺序返回。“filesort” 并不一定是用文件,而是 MySQL 的术语,意思是要在内存里或磁盘里做排序操作。
- 大表
ORDER BY
没有合适的索引时容易触发,可能会产生大量磁盘临时文件,导致慢。
- Using temporary
- 表示执行这条 SQL 时需要用到 临时表 来存放中间结果。常见于
GROUP BY
、DISTINCT
、UNION
、有子查询的复杂ORDER BY
等场景。 - 代价是内存放不下就会写磁盘,慢且占 IO。
- Impossible WHERE
- 表示 WHERE 条件永远为假,这条语句根本不会返回数据。通常是写错了条件或者逻辑冲突,比如:
SELECT * FROM user WHERE 1 = 0; 或者 SELECT * FROM user WHERE id < 1 AND id > 10;
有时候是调试 OK,有时候是写错条件了要赶紧排查。
- Using join buffer
- 表示执行
JOIN
时,某个表没有走索引,只能用 块嵌套循环 来做匹配。MySQL 会把驱动表(外表)中的行放到一个join buffer
(内存块)里,然后一条条对比匹配内表。 - 常见于被
JOIN
的表没有合适的索引,导致全表扫描做匹配。通常会让EXPLAIN
里的type
看到ALL
(全表扫)。 - 后果就是块读性能远不如索引匹配,特别是大表
JOIN
时很耗时。