必须将tmp_table_size与max_heap_table_size设为相同值,否则内存临时表上限取二者较小值;若不一致,调大tmp_table_size无效,易致created_tmp_disk_tables持续增长。

直接调大 tmp_table_size 通常治标不治本——真正卡住内存临时表的,是它和 max_heap_table_size 中更小的那个值。只改一个,等于没改。
先确认是不是真被参数卡住了
执行这条语句查当前实际生效值:
SELECT @@tmp_table_size, @@max_heap_table_size;
如果两个值不相等(比如一个是 128M,另一个是 16M),那内存临时表上限就是 16M,再大的中间结果都会立刻落盘。同时看监控指标:
-
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables'; 持续上升,且占
Created_tmp_tables总量超 15%,基本可断定是内存不足导致频繁落盘 -
SELECT @@tmpdir; 查 MySQL 实际用的临时目录,再用
df -h看该路径磁盘是否真的快满了(排除误判)
同步调大两个关键参数
二者必须设为相同值,推荐从 128M 或 256M 起步(具体看服务器内存和并发量):
- 会话级临时验证:
SET SESSION tmp_table_size = 268435456;
SET SESSION max_heap_table_size = 268435456; - 永久生效:在
my.cnf的[mysqld]段里写明:
tmp_table_size = 256M
max_heap_table_size = 256M - 重启或热加载后,务必再执行
SHOW VARIABLES确认两者已一致
别只盯着参数,还要看查询本身
很多“大排序”其实没必要生成巨量中间结果。典型高危场景:
-
ORDER BY或GROUP BY字段没索引,尤其还带函数(如GROUP BY UPPER(name)) - 查询返回大量字段(
SELECT *)但只用其中几列做排序/分页,却让整个结果集进临时表 - 多表 JOIN 后再
ORDER BY非驱动表字段,触发强制临时表
优化建议:
- 对排序/分组字段补索引;避免在这些字段上用函数
- 把“取ID列表 + 回表查详情”拆成两步(如先
SELECT id FROM ... ORDER BY x LIMIT 20,再SELECT * FROM ... WHERE id IN (...)) - 检查执行计划,确认
Using temporary是否真必要,能否通过覆盖索引或重写逻辑绕过
留意云环境的额外限制
像阿里云 RDS 这类托管服务,还有 loose_rds_max_tmp_disk_space 这个隐藏上限(默认 10GB)。即使你把内存参数调得再大,只要磁盘临时表总用量超限,照样报错 The table is full。可通过以下方式确认:
- SHOW VARIABLES LIKE 'loose_rds_max_tmp_disk_space';
- 观察错误日志中是否出现
disk space exhausted for temp tables类提示
若确认是该限制导致,需提工单申请调高,或进一步压缩单次查询的临时表体积。











