MySQL 5.7临时表撑爆磁盘主因是tmp_table_size与max_heap_table_size未同步配置,导致内存阈值实际仅为默认16MB,超限即全量落盘至无上限的ibtmp1或/tmp;必须二者设为相等(如均为64M),并配合重启生效,ibtmp1已暴涨则需重启释放。

MySQL 5.7 中临时表撑爆磁盘,根本不是 tmp_table_size 配得小——而是它配得太大,又没配好 max_heap_table_size,导致内存临时表“假大”,一超就全落盘,瞬间写满 ibtmp1 或 /tmp。
为什么调大 tmp_table_size 反而更危险
MySQL 判断是否用内存临时表,要看两个参数的**较小值**:tmp_table_size 和 max_heap_table_size。哪怕你把 tmp_table_size 设成 2G,但 max_heap_table_size 还是默认的 16M,那实际阈值就是 16M。一旦查询生成的临时结果 >16M,就会强制落盘到 ibtmp1(InnoDB 临时表)或 /tmp(MyISAM 临时表),而这两个位置通常没做空间限制。
-
ibtmp1默认配置是ibtmp1:12M:autoextend,无上限,涨到 300G 都不报错 -
/tmp目录往往和系统根分区共用,一写满直接卡死 mysqld - 执行
EXPLAIN看到Using temporary,说明已触发临时表;再查SHOW STATUS LIKE 'Created_tmp_disk_tables',如果这个值飙升,就是内存不够、全在刷磁盘
怎么安全地调参:必须同步改两个值
只改 tmp_table_size 是无效操作。真正起作用的是两者的交集,且要结合业务查询特征来设:
- 先观察峰值:查
SHOW GLOBAL STATUS LIKE 'Created_tmp%',计算Created_tmp_disk_tables / Created_tmp_tables比值,超过 25% 就说明落盘太频繁 - 再看单次查询:用
EXPLAIN FORMAT=JSON查大查询的estimated_row_count× 单行平均字节数,估算临时结果大小 - 最终设置:让
tmp_table_size = max_heap_table_size,例如都设为64M(不建议超过 128M,内存比磁盘金贵得多) - 注意:修改后需重启或
SET PERSIST(5.7.20+),仅SET GLOBAL会随重启丢失
ibtmp1 已经涨到上百 GB 怎么办
ibtmp1 文件**无法在线收缩**,即使删了临时表、杀掉线程,文件体积也不会变小。这是 InnoDB 的设计限制:
- 唯一可靠释放方式:重启 MySQL 实例(5.7+ 会在启动时自动重建
ibtmp1为初始 12M) - 重启前务必确认:没有长事务、没有正在运行的 DDL、主从延迟为 0
- 如果不能重启,可临时把
innodb_temp_data_file_path改成带:max:2G限制(如ibtmp1:12M:autoextend:max:2G),避免继续暴涨 - 切勿手动删除
ibtmp1文件——mysqld 启动时会因找不到文件而失败
最常被忽略的一点:很多 DBA 调完参数就以为万事大吉,但没关掉 log_queries_not_using_indexes,导致慢日志里大量 ORDER BY、GROUP BY 查询被反复记录,这些查询恰恰是最容易触发临时表的。真要治本,得配合 INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO 定位具体是哪个线程、哪条 SQL 在狂写 ibtmp1,而不是只靠调参硬扛。


















