升级后group by/distinct变慢,主因是mysql 8.0.16起internal_tmp_mem_storage_engine默认从memory切为temptable,而temptable_max_ram仍为默认1gb,导致隐式临时表频繁落盘;需检查并调大temptable_max_ram至与tmp_table_size/max_heap_table_size匹配。

升级后临时表性能突然变差,大概率不是SQL写法问题,而是internal_tmp_mem_storage_engine默认值变了,且配套参数没跟上。
为什么升级后 GROUP BY / DISTINCT 变慢了?
MySQL 8.0.16 起,internal_tmp_mem_storage_engine 默认从 MEMORY 切成了 TEMPTABLE。这个切换本身是优化,但如果你沿用 5.7 的配置(比如只调大了 tmp_table_size),TEMPTABLE 实际能用的内存池仍被卡在默认的 1GB 以内,而旧版 MEMORY 表是直接硬扛到 max_heap_table_size 才报错——结果就是:原来全程内存跑的查询,现在频繁分页落盘,IO 暴增。
-
TEMPTABLE是否落盘,看的是temptable_max_ram,不是tmp_table_size -
tmp_table_size和max_heap_table_size对TEMPTABLE仅间接起作用:只有当它们中较小值 ≤temptable_max_ram时,TEMPTABLE才可能全程走内存 - 升级后没动配置,
temptable_max_ram仍是默认 1G,但业务数据量已增长,隐式临时表一超就写磁盘
怎么快速验证是不是这个原因?
连上库,执行这两条命令:
SELECT @@internal_tmp_mem_storage_engine;
SELECT @@temptable_max_ram, @@tmp_table_size, @@max_heap_table_size;
如果返回 TEMPTABLE 且 temptable_max_ram 是 1073741824(即 1GB),而另外两个参数远大于它(比如设成了 2G),那基本就是它了。
- 别只查
tmp_table_size就以为“临时表内存够大”——对TEMPTABLE来说,它是失效的 - 错误日志里如果频繁出现
Writing temp table to disk或Using external sort,也是强信号
调整 internal_tmp_mem_storage_engine 配置要注意什么?
不建议强行切回 MEMORY,除非你确认所有隐式临时表都不含 TEXT/BLOB、行长度可控、并发不高。更稳妥的是调优 TEMPTABLE 行为:
- 在
[mysqld]段下设置temptable_max_ram,值建议设为tmp_table_size和max_heap_table_size中的较小值(例如都设 2G,这里就设2147483648) - 如果机器内存紧张或跑在容器里,把
temptable_use_mmap设为OFF,避免 mmap 占用过多虚拟地址空间引发 OOM - 改完必须重启 MySQL 生效,热加载不支持这个参数
- 不要在会话级 SET 这个变量——
internal_tmp_mem_storage_engine是全局只读变量,SET 会报错
升级后还有临时表报错怎么办?
常见两类报错,和引擎切换强相关:
-
ERROR 1163 (42000): The used table type doesn't support BLOB/TEXT columns→ 这是MEMORY引擎在作祟,说明某处显式创建了TEMPORARY TABLE ... ENGINE=MEMORY且含大字段,得改成ENGINE=InnoDB或删掉 ENGINE 子句让其走默认TEMPTABLE -
ERROR 1114 (HY000): The table is full→ 大概率是没关temptable_use_mmap,容器环境 mmap 分配失败,或者temptable_max_ram设得太小又没配好tmpdir导致磁盘写失败
真正麻烦的点在于:这些行为变化不会在慢日志里直接体现,也不会报错说“你该调 temptable_max_ram”,得靠组合判断。别只盯着 SQL 改写,先确认引擎和内存池的实际边界在哪。











