extra列出现using temporary或using filesort即表明存在性能开销;前者源于union、derived子查询、无索引group by/order by等,后者因order by未走索引或复合索引顺序不匹配;需结合select_type和table列定位临时表来源,并关注tmp_table_size参数以防磁盘临时表。

看Extra列里有没有Using temporary或Using filesort
这是最直接的判断依据。Navicat执行计划表格中,Extra列一旦出现Using temporary或Using filesort,就说明MySQL在执行过程中不得不创建临时表或进行额外排序——这两者都是典型的性能开销信号。
注意:Using temporary不等于“你写了CREATE TEMPORARY TABLE”,而是优化器内部物化中间结果;Using filesort也不代表一定用了磁盘文件,它只是表示排序没走索引,哪怕在内存完成,也已脱离高效路径。
-
Using temporary常见于:UNION、FROM子句中的子查询(select_type = DERIVED)、GROUP BY或ORDER BY字段无可用索引、多表JOIN时驱动表选择错误 -
Using filesort典型诱因:ORDER BY字段未建索引、复合索引顺序与ORDER BY不一致(如索引是(a, b)却ORDER BY b)、WHERE条件用了函数导致索引失效 - 两者可能同时出现:比如
SELECT * FROM t ORDER BY c LIMIT 10,c无索引 →Extra显示Using filesort; Using temporary(因LIMIT需缓存前N行)
结合select_type和table列交叉验证临时表来源
单看Extra不够精准,容易误判。真正要定位“谁触发了临时表”,得拉通看select_type和table两列:
-
select_type = DERIVED且table显示<derivedn></derivedn>:说明FROM里的子查询被物化成临时表,N对应其id值 -
select_type = UNION或UNION RESULT:只要用了UNION(哪怕是UNION ALL),必然经过临时表合并结果集 -
table列出现<unionm></unionm>:明确告诉你这是id=M和id=N两个查询的合并结果,背后就是临时表 -
select_type = DEPENDENT SUBQUERY但Extra没写Using temporary?别掉以轻心——如果该子查询含GROUP BY或DISTINCT,仍可能隐式生成临时表,需单独EXPLAIN子查询验证
区分内存临时表和磁盘临时表的关键参数
MySQL默认优先用内存建临时表,但tmp_table_size和max_heap_table_size设得太小,就会把本可内存完成的操作硬生生拖到磁盘,性能断崖下跌。这不是执行计划能直接显示的,但你可以快速推断:
- 如果
Extra只写Using temporary,没提On disk,大概率还在内存里;但若查询返回几万行+,而tmp_table_size只有2M(默认值),基本已经落盘 - 查当前值:
SHOW VARIABLES LIKE 'tmp_table_size';和SHOW VARIABLES LIKE 'max_heap_table_size';,二者取较小值才是实际上限 - 线上建议调高:比如设为64M(
SET GLOBAL tmp_table_size = 67108864;),但要注意全局生效影响所有连接内存占用 - 注意:
GROUP BY若无法用松散索引扫描(Loose Index Scan),即使数据量小,也会强制走临时表+排序,和内存大小无关
ORDER BY和GROUP BY没走索引时的典型表现
很多人以为“没全表扫描就行”,其实type是range或ref,照样可能因排序/分组低效拖垮性能。重点盯住这两点:
-
ORDER BY字段必须出现在索引最左前缀,且顺序严格匹配:索引(a, b, c)支持ORDER BY a, b,不支持ORDER BY b, c;若还带WHERE a = ?,则ORDER BY b, c可以走索引 -
GROUP BY同理,且注意SQL_MODE是否开启ONLY_FULL_GROUP_BY——开启后,SELECT里非GROUP BY字段若没聚合,会直接报错,反而帮你提前暴露问题 - 复合索引覆盖场景:若
SELECT a, b FROM t WHERE a = 1 ORDER BY b,索引(a, b)就能避免Using filesort;但若写成SELECT * ...,即使有(a, b)索引,仍可能因回表+排序触发Using temporary
临时表和文件排序不是非黑即白的“有或无”,而是程度问题。同一个Using temporary,在100行结果集上可能是毫秒级,在百万行上就是秒级甚至超时。真正要命的,往往是那些Extra看着干净、rows估算也不大,但实际执行时因隐式类型转换或字符集不一致,让索引彻底失效,最终退化成全表扫描+内存排序的组合拳。











