必须同步设置tmp_table_size和max_heap_table_size为相同值,因mysql取二者较小值作为内存临时表上限;若不一致(如tmp_table_size=512m但max_heap_table_size仍为默认16mb),则超限查询强制落盘,导致created_tmp_disk_tables激增及磁盘空间耗尽。

只调 tmp_table_size 基本没用,必须同步设好 max_heap_table_size,否则 MySQL 永远按两者中更小的那个值截断。
为什么改了 tmp_table_size 还报 “The table is full”
MySQL 判断是否能走内存临时表,不是看 tmp_table_size 多大,而是取 tmp_table_size 和 max_heap_table_size 的较小值。常见错误是:配置里写了 tmp_table_size = 512M,但忘了改 max_heap_table_size,它还卡在默认的 16MB(即 16777216 字节)。结果所有超过 16MB 的 GROUP BY 或 ORDER BY 查询,全被强制落盘——如果 @@tmpdir 又在根分区,ibtmp1 或 /tmp 就会一路暴涨到爆满。
- 执行
SELECT @@tmp_table_size, @@max_heap_table_size;确认两者数值是否一致(单位是字节) - 查
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';,如果这个值每秒涨几十次,基本就是内存阈值被卡死了 - 别信慢日志里 “Using temporary” 就代表问题出在参数上——它也可能是因为
SELECT里带了TEXT字段,这种情况下再大的内存也拦不住落盘
怎么安全地设两个参数为相同值
不能只写一行配置,也不能靠 SET GLOBAL 临时改——旧连接不生效,重启后又丢失。必须在配置文件里显式并列写两行,且值完全相等。
- 在
my.cnf的[mysqld]段里加:tmp_table_size = 268435456max_heap_table_size = 268435456
(即 256MB,注意不要写256M以外的单位,MB或G会解析失败) - 改完必须重启
mysqld;5.7.20+ 可用SET PERSIST持久化,但依然要重启才对已有连接生效 - 上线前先算余量:单个连接最多吃掉这个大小的内存,如果
max_connections = 500,256MB × 500 ≈ 128GB,远超物理内存,就得往下压——建议上限 ≤ 总内存的 20%
MySQL 8.0+ 升级后 tmp_table_size 不起作用了
MySQL 8.0 已彻底移除 tmp_table_size 参数。如果你从 5.7 升级上来,配置文件里还留着它,mysqld 启动时会静默忽略,不报错也不警告。运行 SELECT @@tmp_table_size 会返回 0 或直接报错 Unknown system variable 'tmp_table_size'。
- 真正起作用的是:
max_heap_table_size(控制内存临时表上限)internal_tmp_mem_storage_engine(默认为TempTable)temptable_max_ram(8.0.16+ 新增,决定 TEMPTABLE 引擎总内存池上限,默认物理内存的 3%,不支持动态修改) -
temptable_max_ram必须写进配置文件,例如:temptable_max_ram = 4G(8.0.23+ 支持单位,旧版请写4294967296) - 重启前务必执行:
SET GLOBAL innodb_fast_shutdown = 0;,再SHUTDOWN;,确保旧ibtmp1可被安全重建
最容易被忽略的点是:即使你把两个参数设得再大,只要 SQL 里用了 BLOB/TEXT、未索引的函数表达式(如 GROUP BY UPPER(name))、或显式指定磁盘引擎,MySQL 就根本不会尝试建内存临时表——参数再大也白搭。先看 EXPLAIN FORMAT=JSON 里的 using_temporary_table 和 using_filesort,再动手调参。











