大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

用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 BYDISTINCTORDER BY无法利用索引的场景。临时表可能存储在内存中,也可能写入磁盘——一旦写磁盘,性能会急剧下降。

示例​:

SELECT category, COUNT(*) FROM products GROUP BY category;

如果category没有索引,Extra会显示Using temporary——MySQL需要建临时表来存储分组结果。

优化建议​:给GROUP BYDISTINCT的列加索引,让分组操作走索引,消除临时表。

信号五:Using filesort——文件排序,性能警报

Using filesort表示MySQL无法利用索引完成排序,需要进行额外的排序操作。

“filesort”这个名字容易让人误解——它不一定使用文件,也可能在内存中完成排序,但无论哪种方式,都比走索引排序慢得多。

示例​:

SELECT * FROM products ORDER BY sales DESC LIMIT 10;

如果sales没有索引,Extra会显示Using filesort

优化建议​:给ORDER BY的列加索引,让排序走索引。注意:如果ORDER BYWHERE同时存在,复合索引的顺序需要同时考虑两者的需求。

信号六:Using temporary; Using filesort——双重警报

Using temporaryUsing filesort同时出现,说明查询不仅需要临时表,还需要对临时表进行排序。

这是最糟糕的情况之一——MySQL先建临时表存中间结果,再对临时表做排序。如果数据量大,临时表可能写入磁盘,排序又消耗大量CPU和内存,性能必然崩盘。

常见场景​:GROUP BY的列和ORDER BY的列不同,且都没有合适的索引。

优化建议​:重新设计索引,让GROUP BYORDER 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_switchmrr是否开启。

总结

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 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐