MySQL 报错 “The table ... is full” 排查:临时表、TempTable 与磁盘空间问题解析
MySQL 报错 The table ... is full 时,很多人第一反应是“磁盘满了”。这确实是常见原因之一,但并不是唯一原因。尤其在 MySQL 8.0 中,复杂 SQL 触发内部临时表、TempTable 内存限制、InnoDB 临时表空间、tmpdir 空间、早期版本 Bug 等,都可能导致类似报错。
这篇文章结合一次线上故障,整理 The table '/tmp/#sql...' is full 的排查路径、原因分类、临时止血、参数调整、SQL 优化和版本升级建议。
问题背景
某次公司程序在使用 MySQL 过程中,出现了如下错误:
The table '/tmp/#sql1_34519d_0' is full
后续数据库出现 OOM,最后数据库自动重启。
当时时间线大致如下:
- 5:00 ~ 7:30:持续出现
The table ... is full错误。 - 8:00:出现更多数据库异常。
- 9:40:数据库自动重启。
原始截图保留如下:


报错含义
The table ... is full 的字面意思是:MySQL 需要向某张表继续写入数据,但该表已经无法继续扩展。
这里的“表”不一定是业务表,也可能是:
- 内部临时表。
- 磁盘临时表。
- InnoDB 临时表空间中的临时表。
- MEMORY 引擎临时表。
- TempTable 引擎临时表。
如果路径中出现类似:
/tmp/#sql1_34519d_0
通常说明问题与 MySQL 执行 SQL 时创建的临时表有关。
MySQL 什么时候会创建内部临时表
MySQL 在执行某些 SQL 时,会自动创建内部临时表。常见场景包括:
GROUP BYORDER BYDISTINCTUNION- 派生表 derived table
- 公共表表达式 CTE
- 窗口函数
- 多表 JOIN 后需要排序或聚合
- 某些不能直接使用索引完成的查询
例如:
SELECT user_id, COUNT(*)
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY user_id
ORDER BY COUNT(*) DESC;
如果缺少合适索引,或者中间结果集很大,就可能产生大量临时表数据。
常见原因分类
1. 磁盘或 tmpdir 空间不足
如果 MySQL 临时文件写在 /tmp,而 /tmp 所在分区空间不足,就可能报错。
排查命令:
df -h
mount | grep tmp
ls -lh /tmp | head
MySQL 参数:
SHOW VARIABLES LIKE 'tmpdir';
如果 tmpdir 指向空间较小的分区,可以考虑调整到更大的磁盘分区。
2. InnoDB 临时表空间不足
MySQL 使用磁盘内部临时表时,可能涉及 InnoDB 临时表空间。需要关注:
SHOW VARIABLES LIKE 'innodb_temp_data_file_path';
如果临时表空间增长受限,也可能触发 table is full。
3. TempTable 内存限制
MySQL 8.0 默认内部临时表引擎通常是 TempTable,可通过以下参数查看:
SHOW VARIABLES LIKE 'internal_tmp_mem_storage_engine';
SHOW VARIABLES LIKE 'temptable%';
SHOW VARIABLES LIKE 'tmp_table_size';
SHOW VARIABLES LIKE 'max_heap_table_size';
相关参数包括:
| 参数 | 作用 |
|---|---|
internal_tmp_mem_storage_engine |
内部内存临时表引擎,可为 TempTable 或 MEMORY |
tmp_table_size |
内部临时表大小限制,MySQL 8.0.28 后对单个 TempTable 内存临时表也有影响 |
max_heap_table_size |
MEMORY 表最大大小 |
temptable_max_ram |
TempTable 可使用的内存上限 |
temptable_max_mmap |
TempTable 可使用 mmap 的上限 |
tmpdir |
临时文件目录 |
不同 MySQL 8.0 小版本对这些参数的行为存在差异,调整前一定要先确认当前版本。
4. SQL 产生了过大的临时表
即使磁盘和参数都没问题,SQL 本身也可能导致临时表异常膨胀。典型问题包括:
- 查询范围过大。
- 缺少过滤条件。
GROUP BY/ORDER BY无法利用索引。- 多表 JOIN 中间结果集远大于最终结果。
UNION去重导致排序和临时表。- 大字段参与排序、分组或临时表。
排查 SQL:
EXPLAIN FORMAT=JSON <problem_sql>;
重点关注执行计划中是否出现:
- temporary table
- filesort
- materialized derived table
- using temporary
- using filesort
5. MySQL 8.0 早期版本 Bug
这次故障中,排查到 MySQL 8.0 早期版本 TempTable 引擎相关问题。官方 Bug 记录中曾出现复杂查询使用临时表进行聚合时,耗尽 TempTable 可用内存并触发 table is full 的情况。
当时环境为 MySQL 8.0.16,最终判断与 MySQL 8.0 早期 TempTable 问题高度相关。官方在后续版本中修复了相关问题,因此升级版本是更稳妥的长期方案。
排查步骤
建议按下面顺序排查。
第一步:确认错误来源
查看 MySQL error log 和应用日志:
grep -i "table.*full" /path/to/mysql/error.log
grep -i "#sql" /path/to/mysql/error.log
如果报错路径类似 /tmp/#sql...,优先按内部临时表方向排查。
第二步:确认磁盘和 tmpdir
df -h
du -sh /tmp
SHOW VARIABLES LIKE 'tmpdir';
第三步:查看临时表相关状态
SHOW GLOBAL STATUS LIKE 'Created_tmp%';
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';
关注:
Created_tmp_tablesCreated_tmp_disk_tablesCreated_tmp_files
如果磁盘临时表比例很高,说明 SQL 或参数需要重点优化。
第四步:查看关键参数
SHOW VARIABLES LIKE 'version';
SHOW VARIABLES LIKE 'internal_tmp_mem_storage_engine';
SHOW VARIABLES LIKE 'tmp_table_size';
SHOW VARIABLES LIKE 'max_heap_table_size';
SHOW VARIABLES LIKE 'temptable%';
SHOW VARIABLES LIKE 'innodb_temp_data_file_path';
第五步:定位问题 SQL
可以从慢查询日志、应用日志、监控平台中定位问题时间段的 SQL。
EXPLAIN FORMAT=JSON <problem_sql>;
重点看是否存在大范围扫描、临时表、文件排序、派生表物化等。
解决方案
1. 临时止血
如果问题正在发生,可以先考虑:
- 停止或限流触发问题的任务。
- 杀掉异常 SQL。
- 清理
tmpdir所在分区空间。 - 扩大临时目录所在磁盘空间。
- 临时调整相关参数。
查看正在执行 SQL:
SHOW FULL PROCESSLIST;
终止问题线程:
KILL <thread_id>;
2. 参数调整
如果确认是 TempTable 资源限制,可以评估调整:
SHOW VARIABLES LIKE 'internal_tmp_mem_storage_engine';
SHOW VARIABLES LIKE 'temptable_max_ram';
SHOW VARIABLES LIKE 'tmp_table_size';
早期 MySQL 8.0 版本中,有人通过切换内部临时表引擎临时规避问题:
SET GLOBAL internal_tmp_mem_storage_engine = MEMORY;
但这不是通用银弹。原因是:
- MEMORY 引擎不支持 BLOB / TEXT 等大字段场景。
- 行格式和内存占用方式不同。
- 参数切换可能影响其他 SQL。
- 新版本 MySQL 的 TempTable 行为已经变化。
生产环境调整前必须在测试环境验证,并结合当前 MySQL 版本确认影响。
3. SQL 优化
SQL 优化通常比单纯调大参数更可靠:
- 给
WHERE、JOIN、GROUP BY、ORDER BY涉及字段建立合适索引。 - 减少参与排序和分组的字段数量。
- 避免大字段进入临时表。
- 将超大查询拆分为分批处理。
- 避免无必要的
UNION去重,能用UNION ALL时不要用UNION。 - 控制报表类 SQL 的查询时间范围。
4. 版本升级
如果使用 MySQL 8.0 早期版本,并且命中 TempTable 相关 Bug,建议升级到修复后的稳定版本。
这次故障对应的经验是:
- MySQL 8.0.16 存在较多早期版本问题。
- 官方后续版本修复过 TempTable 相关 Bug。
- 长期方案应优先考虑升级,而不是永久依赖参数绕过。
生产预防清单
建议建立以下监控:
/tmp和 MySQLtmpdir所在分区使用率。- InnoDB 临时表空间增长。
Created_tmp_disk_tables数量和比例。- 慢查询中
Using temporary、Using filesort的 SQL。 - MySQL error log 中
table is full、#sql关键字。 - 报表任务和批处理任务的执行时间、扫描行数。
建议治理:
- 报表 SQL 必须经过 explain 审查。
- 大查询要限制时间范围和分页。
- 避免业务高峰执行重型统计任务。
- MySQL 小版本不要长期停留在早期 8.0 版本。
- 参数调整必须记录变更和回滚方案。
总结
The table ... is full 不一定是业务表满了,也不一定只是磁盘满了。排查时应按以下路径判断:
- 是否是
/tmp/#sql...内部临时表。 tmpdir和磁盘空间是否充足。- InnoDB 临时表空间是否受限。
- TempTable、MEMORY、
tmp_table_size等参数是否合理。 - SQL 是否产生了过大的临时表。
- 当前 MySQL 版本是否存在相关 Bug。
本次案例的最终建议是:优先升级到修复后的 MySQL 版本;如短期无法升级,再谨慎评估 internal_tmp_mem_storage_engine=MEMORY 等参数绕过方案,并同步优化问题 SQL。