MySQL 8.0 默认用 TempTable 而非 MEMORY,因 MEMORY 不支持 TEXT/BLOB、超内存即报错且不降级,而 TempTable 支持变长字段、按页落盘、内存更紧凑;落盘后选 InnoDB 是因 MyISAM 已弃用且无崩溃恢复能力。

MySQL 8.0 为什么默认用 TempTable 而不是 MEMORY?
因为 MEMORY 引擎在 8.0 场景下已不可靠:它不支持 TEXT/BLOB,一遇到就直接报错 ERROR 1114;超内存就崩,不降级;且受 max_heap_table_size 硬截断,无法估算中间结果膨胀。TempTable 是专为隐式临时表设计的内存引擎,支持变长字段、按页落盘、内存使用更紧凑,还能复用 MySQL 内存池管理机制。
-
internal_tmp_mem_storage_engine默认值从MEMORY改为TEMPTABLE(注意拼写,不是 TEMPORARY) - 显式建表仍可用
CREATE TEMPORARY TABLE ... ENGINE=MEMORY,但优化器自动创建的临时表(如GROUP BY、UNION、窗口函数中间结果)走的是 TempTable 路径 - 查当前设置:
SELECT @@internal_tmp_mem_storage_engine;,返回TEMPTABLE才表示生效
为什么落盘后选 InnoDB 而不是 MyISAM 或其他?
MyISAM 在 8.0+ 已被官方弃用,internal_tmp_disk_storage_engine 默认值就是 InnoDB,且无法设回 MyISAM(8.0.30+ 直接移除支持)。选 InnoDB 不是性能最优解,而是崩溃安全刚需:临时表落盘后若遇 crash,只有 InnoDB 能靠 redo log 和双写缓冲恢复一致状态;MyISAM 落盘即裸文件,crash 后大概率损坏,连 SELECT 都可能失败。
- 落盘位置不是
/tmp,而是共享临时表空间ibtmp1,路径由innodb_temp_data_file_path控制 - MyISAM 作为磁盘临时表引擎在 8.0 中已无意义:它不支持事务、无崩溃恢复、与系统表引擎不统一,主从复制下还会触发
ER_UNKNOWN_STORAGE_ENGINE - 你看到
Created_tmp_disk_tables上升,不代表数据写进了tmpdir,大概率已在ibtmp1里膨胀
temptable_max_ram 是什么?为什么调它比调 tmp_table_size 更关键?
temptable_max_ram 是 TempTable 引擎的专属内存上限,默认为物理内存的 3%(上限 4 GiB),它决定“内存阶段”能撑多大。而 tmp_table_size 和 max_heap_table_size 只对 MEMORY 引擎起硬限制作用,对 TempTable 仅间接影响初始分配策略——哪怕你把它们设到 2G,只要 temptable_max_ram 还是默认 1G,TempTable 仍会在 1G 后静默切到 InnoDB。
- 这个参数必须在配置文件中设置,不支持
SET GLOBAL - 单位建议用
G(如temptable_max_ram = 2G),MySQL 8.0.23+ 才完全支持M缩写 - 盲目调高有风险:设太大可能掩盖 SQL 本身问题(比如缺索引导致中间结果爆炸),甚至引发系统 OOM
怎么确认某条 SQL 实际用了哪种临时表引擎?
不能只看变量值,得抓运行时行为。最准的方式是开 optimizer trace 或查慢日志中的执行计划备注:
- 会话内执行:
SET optimizer_trace="enabled=on";,跑完 SQL 后查SELECT * FROM information_schema.OPTIMIZER_TRACE,搜索"tmp_table_storage_engine" - 开启慢日志:
SET GLOBAL slow_query_log = ON;+SET GLOBAL log_output = 'TABLE';,再查mysql.slow_log,看 Query_time 行末尾是否带Using temporary (InnoDB)或Using temporary (TempTable) - 注意:
SHOW VARIABLES LIKE 'internal_tmp_storage_engine'返回的值和实际引擎可能不一致——这个变量名本身就有误导性,它只管“内存阶段”,不管落盘逻辑
真正难处理的不是“选哪个引擎”,而是当查询含 JSON_EXTRACT、utf8mb4_0900_as_cs 排序或列太多时,TempTable 会因估算不准直接 fallback 到 InnoDB,此时既没报错也没提示,只能靠 trace 或慢日志反推。这种静默切换,最容易在报表类场景里突然拖垮磁盘 I/O。


















