Using temporary 和 Using filesort 同时出现,根本原因是MySQL无法用索引直接组织中间结果与排序:典型场景包括多表JOIN后按非驱动表字段排序、间接关联导致必须缓存中间结果、DISTINCT/UNION无覆盖索引支撑,以及TEXT/BLOB字段强制落盘。

Using temporary 出现的典型场景
MySQL 创建临时表不是因为“写错了 SQL”,而是它发现无法用索引直接组织中间结果。常见触发点包括:
-
ORDER BY或GROUP BY字段与驱动表的索引顺序不一致,比如多表 JOIN 后按非驱动表字段排序 - 多表 LEFT JOIN 中存在“间接关联”(如 A→B→C),MySQL 无法一次性走索引链,必须先存下中间结果再处理
-
DISTINCT、UNION、窗口函数或子查询中涉及去重/聚合,且无覆盖索引支撑 - 查询中包含
TEXT/BLOB字段,强制临时表落盘为 MyISAM(哪怕数据量很小)
注意:Using temporary 本身不等于慢——只要临时表能留在内存里(Created_tmp_disk_tables 值稳定为 0),开销可控。真正危险的是它频繁转成磁盘表。
Using filesort 的真实含义和常见误判
Using filesort 不代表一定用了磁盘文件,只是说明 MySQL 没法靠索引物理顺序直接返回有序结果,必须额外启动一套排序逻辑。它常被误认为“很糟”,但其实:
- 如果排序数据量小(
rows少)、sort_buffer_size足够,全程在内存完成,性能影响微乎其微 - 它可能只作用于单表(比如
SELECT * FROM user ORDER BY create_time),也可能出现在 JOIN 后的临时表上(此时 Extra 会同时出现Using temporary; Using filesort) - 触发原因往往是
ORDER BY字段没索引、复合索引最左匹配失效、或WHERE中有范围条件(如id > 100)导致后续索引字段无法用于排序
一个关键细节:max_length_for_sort_data 限制了单行参与排序的数据长度。若 SELECT 的字段太多(尤其含大文本),即使有索引,MySQL 也可能退回到双路排序并标记 Using filesort。
为什么二者经常一起出现?
当执行计划里同时看到 Using temporary; Using filesort,通常意味着:MySQL 先把 JOIN 结果塞进临时表(因为无法流式输出),然后再对这张临时表做排序。典型结构是:
- 主表 + 多个间接关联表(如 A→B→C,C 不直接连 A)
-
ORDER BY字段属于最内层非驱动表(如 C 表的created_at) - 没有覆盖索引能把所有 JOIN 条件 + 排序字段 + 查询字段一并包含
这时优化优先级很明确:先消灭 Using temporary(加覆盖索引或重构 JOIN 顺序),再看 Using filesort 是否随之消失。强行调大 sort_buffer_size 对这种组合几乎无效——排序对象是临时表,而临时表本身已经因设计问题被迫生成。
最容易被忽略的复杂点
很多同学查完 EXPLAIN 就去改配置,但真正卡住性能的,往往藏在两个地方:
- JOIN 顺序不可控时,
STRAIGHT_JOIN可能比索引更直接——让 MySQL 按你指定的顺序驱动,避免它自己选错表引发临时表 -
ORDER BY和LIMIT共存时,如果排序字段有索引但未覆盖全部 SELECT 字段,MySQL 可能放弃索引排序,转而用临时表+filesort来减少回表次数(这是成本权衡,不是 bug)
换句话说,看到这两个标记,第一反应不该是“调参”,而是打开 SHOW STATUS LIKE 'Created_tmp%' 看落盘比例,再结合实际 rows 和 key_len 判断:到底是索引没建对,还是 SQL 逻辑本身就不适合在数据库层做这个排序。


















