mysql临时表落盘主因是配置或sql写法不当,应通过监控created_tmp_disk_tables占比、调大tmp_table_size/max_heap_table_size、避免text/blob字段及优化sql等手段解决。

绝大多数 MySQL 内部临时表落盘,不是因为数据量真大,而是因为配置、索引或 SQL 写法触发了“不得不写磁盘”的条件。核心解决路径是:让临时表留在内存里,或者干脆不让它生成。
查清是不是真在写磁盘
别猜,先看指标。执行 SHOW STATUS LIKE 'Created_tmp%',重点关注两个值:
-
Created_tmp_tables:总共创建了多少临时表(含内存和磁盘) -
Created_tmp_disk_tables:其中有多少转成了磁盘临时表
如果 Created_tmp_disk_tables 占比超过 5%,就该干预了。注意:这个统计只反映会话级行为,重启后归零,建议搭配监控长期观察。
调大内存临时表上限
MySQL 用 tmp_table_size 和 max_heap_table_size 中的较小值,决定内存临时表能撑多大。只要临时表超限,哪怕只超 1 字节,立刻落盘。
- 两者必须设为相同值,否则容易因不一致导致意外落盘
- 设太小(如默认 16M)会让中等规模 GROUP BY 或 ORDER BY 直接写磁盘
- 设太大(如 >2G)可能引发 OOM,尤其在并发高时;建议从 64M 起步,按
Created_tmp_disk_tables下降趋势逐步调高 - 生效方式:
SET GLOBAL tmp_table_size = 67108864(64M),但需确认用户有 SUPER 权限,且重启后失效;永久生效要写进 my.cnf
避免触发落盘的字段和写法
以下情况会让 MySQL 放弃 Memory 引擎,强制走磁盘临时表:
- 查询中 SELECT 或 GROUP BY 涉及
TEXT、BLOB、JSON字段——哪怕只选一列,整张临时表都得落盘 - 使用
SELECT *从宽表取数,尤其含大字段时,极易超限 -
ORDER BY和GROUP BY作用于不同列,且无复合索引覆盖,优化器大概率建临时表排序再分组 - 在
IN()里塞几百个值,MySQL 可能内部构建哈希临时表,若哈希桶过多也会落盘
改法很简单:显式列出需要的字段,把大字段转成 VARCHAR(1000) 截断;为 ORDER BY + GROUP BY 共同字段建复合索引;用 UNION ALL 替代 UNION 避免去重临时表。
把 tmpdir 挪到独立高速存储
即使部分临时表必须落盘,也别让它挤在系统盘或 /tmp(尤其是 tmpfs 内存挂载)。真实瓶颈常是 I/O 队列打满,而非空间不足。
- 用
SELECT @@tmpdir确认当前路径,常见是/tmp或空(走系统默认) - 新建目录(如
/data/mysql-tmp),确保mysql用户有读写权限 - 在 my.cnf 的
[mysqld]段加tmpdir = /data/mysql-tmp,重启生效 - 配合
chown mysql:mysql /data/mysql-tmp和chmod 755,避免权限拒绝报错
真正容易被忽略的是:改完 tmpdir 后必须验证 SELECT @@tmpdir 是否返回新路径,且该目录 inode 数不能耗尽(df -i 查),否则大量小临时文件照样失败。











