MySQL 8.0.16+内隐临时表默认使用TempTable引擎而非MEMORY,由internal_tmp_mem_storage_engine参数控制;其内存阶段受temptable_max_ram限制,超限后按页落盘至InnoDB磁盘临时表,而非整表降级。

MySQL 8.0 的内隐临时表(即优化器自动创建的、你没写 CREATE TEMPORARY TABLE 的那种)默认不再优先用 MEMORY,而是走 TempTable 引擎;只有当它被迫落盘时,才用 InnoDB —— 这不是“首选”,而是“兜底”。真正该关注的,是为什么它会落盘、以及落盘后为什么选 InnoDB 而不是别的。
internal_tmp_mem_storage_engine 决定内存阶段用什么引擎
MySQL 8.0.16+ 默认值是 TEMPTABLE,不是 MEMORY。这个参数控制的是「隐式临时表在内存中用哪个引擎」:
-
TEMPTABLE支持TEXT/BLOB,能按页落盘,内存使用更紧凑,且不受max_heap_table_size的硬截断(不会报ERROR 1114) -
MEMORY仍可用,但只在显式建表或某些旧路径下触发;它一遇到TEXT就直接失败,超内存就崩,不降级 - 查当前设置:
SELECT @@internal_tmp_mem_storage_engine;
temptable_max_ram 和 tmp_table_size 共同影响是否落盘
很多人以为调大 tmp_table_size 就能阻止落盘,其实不对 —— 对 TEMPTABLE 来说,起决定作用的是 temptable_max_ram(默认 1GB):
- 当分配内存超过
temptable_max_ram,新页直接写入磁盘临时文件(/tmp或tmpdir指定路径),不是整表 dump -
tmp_table_size和max_heap_table_size只间接影响:若其中较小值 ≤temptable_max_ram,TEMPTABLE才可能全程驻留内存 - 盲目调高
tmp_table_size不解决问题,反而可能掩盖 SQL 本身的问题(比如缺索引导致 GROUP BY 数据量爆炸)
internal_tmp_disk_storage_engine 控制落盘后用 InnoDB 的原因
一旦 TEMPTABLE 内存耗尽,MySQL 就需要一个磁盘引擎来承接后续数据 —— 这个选择由 internal_tmp_disk_storage_engine 控制,默认是 InnoDB:
- MySQL 5.7 及以前默认是
MyISAM,因它无事务开销、建表快;但 8.0+ 改为InnoDB,核心原因是崩溃安全和一致性保障 -
InnoDB作为磁盘临时表引擎,能复用已有的缓冲池、redo 日志机制和崩溃恢复流程,运维链路更统一 - 想切回
MyISAM?得先确认skip_myisam=OFF(8.0 默认是ON),再设SET GLOBAL internal_tmp_disk_storage_engine = 'MyISAM';,但 8.0.16+ 已移除 MyISAM 全文索引支持,MATCH AGAINST 类查询会直接失效
Created_tmp_disk_tables 增长快,说明问题不在引擎而在 SQL
监控 SHOW STATUS LIKE 'Created_tmp_disk_tables' 是最直接的信号。如果它占 Created_tmp_tables 比例 >5%,别急着换引擎:
- 先看
EXPLAIN输出里有没有Using temporary+Using filesort同时出现 —— 这往往意味着缺失合适的联合索引 - 检查是否用了不必要的
SELECT *、DISTINCT、多层子查询或窗口函数,这些都容易触发大临时表 - 临时表落盘本身不是 bug,是保护机制;强行压制(比如把
temptable_max_ram设到 4G)可能引发 OOM,尤其在容器或小内存机器上
真正难处理的,从来不是“该用哪个引擎”,而是当 TEMPTABLE 开始分页落盘、InnoDB 临时表空间(ibtmp1)持续膨胀又不释放时,你得意识到:SQL 的中间结果已经失控了——这时候调参只是止痛,重构才是解药。


















