执行计划的“黑话”你听懂了吗?Extra列里藏着的8个性能信号
大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!
用EXPLAIN看执行计划,很多人只看type——不是ALL就放心了。但真正藏性能问题的地方,往往不是type,而是Extra列。
Extra列是执行计划里信息密度最高、也最容易被忽略的部分。它记录了数据库在执行过程中的“额外操作”——比如有没有用临时表、有没有文件排序、有没有用到覆盖索引。这些信号直接告诉你性能瓶颈在哪。
今天我们把Extra列里最常见的8个信号逐一拆开讲清楚。
信号一:Using index——最好的信号
Using index表示查询使用了覆盖索引,即查询所需的所有列都在索引中,不需要回表取数据。
这是Extra列里最好的信号——意味着查询直接从索引返回结果,跳过了回表环节,I/O开销最小。
示例:
CREATE INDEX idx_name_age ON users(name, age);
SELECT name, age FROM users WHERE name = '张三';
Extra列显示Using index,说明这个查询只需要扫描索引就能拿到所有数据。
优化建议:看到Using index说明索引设计得当,不需要额外优化。
信号二:Using where——需要回表过滤
Using where表示存储引擎返回数据后,MySQL Server层还需要进行额外的WHERE条件过滤。
这意味着索引只帮你定位到了数据的位置,但完整的过滤条件需要在回表之后才能完成。如果rows很大且Extra显示Using where,说明回表开销可能很大。
示例:
SELECT * FROM users WHERE name = '张三' AND age = 20;
如果只有name上的索引,没有age,Extra会显示Using where——因为age的过滤需要在回表后进行。
优化建议:考虑创建复合索引(name, age),让过滤在索引层完成,消除Using where。
信号三:Using index condition——索引下推(ICP)
Using index condition表示MySQL使用了索引条件下推(ICP,Index Condition Pushdown) 优化。
ICP是MySQL 5.6引入的优化:原本需要回表后才能过滤的条件,现在可以在索引遍历过程中提前过滤,减少回表次数。
示例:
SELECT * FROM users WHERE name LIKE '张%' AND age = 20;
如果索引是(name, age),Extra会显示Using index condition——因为age=20这个条件被“下推”到了索引层,在回表前就过滤掉了不满足的行。
优化建议:Using index condition是好事,说明ICP生效了。如果想让查询更快,可以考虑把查询改成覆盖索引(Using index)。
信号四:Using temporary——临时表,性能警报
Using temporary表示MySQL需要创建临时表来完成查询。
临时表通常出现在GROUP BY、DISTINCT或ORDER BY无法利用索引的场景。临时表可能存储在内存中,也可能写入磁盘——一旦写磁盘,性能会急剧下降。
示例:
SELECT category, COUNT(*) FROM products GROUP BY category;
如果category没有索引,Extra会显示Using temporary——MySQL需要建临时表来存储分组结果。
优化建议:给GROUP BY或DISTINCT的列加索引,让分组操作走索引,消除临时表。
信号五:Using filesort——文件排序,性能警报
Using filesort表示MySQL无法利用索引完成排序,需要进行额外的排序操作。
“filesort”这个名字容易让人误解——它不一定使用文件,也可能在内存中完成排序,但无论哪种方式,都比走索引排序慢得多。
示例:
SELECT * FROM products ORDER BY sales DESC LIMIT 10;
如果sales没有索引,Extra会显示Using filesort。
优化建议:给ORDER BY的列加索引,让排序走索引。注意:如果ORDER BY和WHERE同时存在,复合索引的顺序需要同时考虑两者的需求。
信号六:Using temporary; Using filesort——双重警报
当Using temporary和Using filesort同时出现,说明查询不仅需要临时表,还需要对临时表进行排序。
这是最糟糕的情况之一——MySQL先建临时表存中间结果,再对临时表做排序。如果数据量大,临时表可能写入磁盘,排序又消耗大量CPU和内存,性能必然崩盘。
常见场景:GROUP BY的列和ORDER BY的列不同,且都没有合适的索引。
优化建议:重新设计索引,让GROUP BY和ORDER BY使用同一个索引,或考虑改写SQL。
信号七:Using join buffer——JOIN无索引
Using join buffer表示JOIN操作中,被驱动表没有使用索引,MySQL使用了连接缓冲区(Join Buffer)来存储驱动表的数据。
这意味着JOIN是“全表扫描+缓冲区”的方式,效率远低于索引JOIN。
优化建议:给被驱动表的连接字段加索引,让JOIN走索引。
信号八:Using MRR——多范围读取优化
Using MRR表示MySQL使用了多范围读取(MRR,Multi-Range Read) 优化。
MRR的原理是:把需要回表的主键先收集起来排序,再批量回表,把随机I/O转换为顺序I/O,减少磁盘寻道开销。
示例:范围查询后需要大量回表时,Extra可能出现Using MRR。
优化建议:Using MRR是好事,说明MySQL帮你优化了回表I/O。如果没出现但回表量很大,可以检查optimizer_switch中mrr是否开启。
总结
Extra列是EXPLAIN里信息密度最高的部分,也是最能反映真实性能问题的部分。把8个信号记牢:
| Extra信号 | 含义 | 判断 |
|---|---|---|
Using index |
覆盖索引 | ✅ 好 |
Using index condition |
索引下推(ICP) | ✅ 较好 |
Using where |
需要回表过滤 | ⚠️ 需关注 |
Using temporary |
需要临时表 | ❌ 需优化 |
Using filesort |
需要额外排序 | ❌ 需优化 |
Using temporary; Using filesort |
临时表+排序 | ❌❌ 严重 |
Using join buffer |
JOIN无索引 | ❌ 需优化 |
Using MRR |
多范围读取优化 | ✅ 好 |
下次用EXPLAIN时,别只看type。把Extra列从头到尾读一遍,这些“黑话”会告诉你性能问题的真正答案。
小耶在手,SQL 不愁
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~
更多推荐


所有评论(0)