执行计划里的 Using temporary 往往被轻轻带过,但它说明 MySQL 不能直接沿现有结构返回结果,需要在执行过程中构造一个中间结果载体。

内部临时表常出现在 GROUP BY、ORDER BY、DISTINCT、UNION、派生表和部分子查询里。它不是坏事,但一旦数据量、字段宽度或排序聚合成本失控,就会从内存结构变成磁盘压力。

先把机制边界说清楚

临时表分为用户显式创建的临时表和优化器自动创建的内部临时表。这里重点看内部临时表:它常出现在 GROUP BY、ORDER BY、DISTINCT、UNION、派生表和某些子查询执行中,用来保存中间结果、去重、排序或聚合。

整体路径

临时表:内存表、磁盘表和大查询的代价

上面这张图先看粗线条:宏观上,内部临时表位于执行器中间层。SQL 产生候选行后,如果现有索引顺序或流式执行无法完成去重、分组或排序,MySQL 就创建内部临时表,把中间行写进去,再基于临时表继续处理后续步骤。数据量小留在内存,超过限制或包含不适合内存的列时就会落盘。

底层流程

临时表:内存表、磁盘表和大查询的代价:执行路径

底层拆解先看数据结构。「临时表」至少涉及下面几类结构:

  • TempTable 引擎:MySQL 8.0 默认的内部内存临时表引擎。
  • MEMORY 引擎:旧版本和特定配置下常见的内存临时表方案。
  • 磁盘临时表:内存放不下或字段不适配时转为磁盘存储。
  • 中间结果行:保存执行阶段需要继续排序、去重或聚合的数据。

再看完整执行流程:

  1. 执行器发现当前路径无法流式完成结果处理。
  2. 创建内部临时表并确定列结构。
  3. 把候选行写入临时表,同时维护去重或聚合状态。
  4. 内存超过阈值或字段不适配时转换为磁盘临时表。
  5. 从临时表读取最终结果并继续 order by、having 或返回。

取舍与边界

版本差异上,MySQL 5.7 常见路径是 MEMORY 临时表,落盘后可能使用 MyISAM。MySQL 8.0 引入 TempTable 作为默认内部临时表引擎,磁盘内部临时表更多使用 InnoDB,整体崩溃安全和大字段处理能力更好,但资源成本并不会消失。

临时表最大的问题是它把一个查询变成了中间数据生产者。中间结果可能比最终返回大很多;落盘后会消耗 IO;并发下大量临时表会争夺内存、临时表空间和磁盘带宽。

典型问题:用机制化例子排查

临时表压力来自中间结果,而不是最终返回行数。DISTINCT、GROUP BY、ORDER BY 如果不能复用索引顺序,就可能先构造一张更大的中间表。

可以落到这些动作:

  • 看到 Using temporary 时,不要只看最终返回行数,要估算中间输入行数。
  • 让 DISTINCT、GROUP BY、ORDER BY 尽量复用同一条索引顺序。
  • 大字段不要进入中间结果,先取主键集合再回表。
  • 监控 Created_tmp_tables、Created_tmp_disk_tables 和临时表空间增长。

收束:临时表是执行器的中间账本

临时表不是错误,但它说明现有结构无法直接给出结果。核心链路要尽量少造中间表,分析链路则要给它隔离资源。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 MySQL」,欢迎关注公众号 「十三Tech」。后续会继续按机制、图解和实战排查这条线更新。

十三Tech公众号二维码