错误28是/tmp或tmpdir分区空间耗尽所致,并非数据库崩溃;需检查tmpdir实际路径、扩容或调大tmp_table_size/max_heap_table_size,根本解法是优化SQL避免临时表。

Got error 28 from storage engine 是磁盘满了吗?
不是“数据库崩了”,而是 MySQL 在执行查询(尤其是 ORDER BY、GROUP BY、大表 JOIN)时,临时需要写磁盘,但 /tmp 或 tmpdir 所在分区没空间了。错误码 28 对应系统级的 ENOSPC —— 真的写不进去了。
常见触发场景:SELECT ... ORDER BY ... LIMIT 大偏移、未加索引的 GROUP BY、CREATE TABLE AS SELECT、ALTER TABLE 重建表。
- 先用
df -h /tmp或df -h看对应tmpdir分区是否 100% 满(注意:有些系统tmpdir指向/var/tmp或/run/mysqld) - 别只看
/根分区,MySQL 的tmpdir可能单独挂载(比如 Docker 容器里映射的小 volume) -
SHOW VARIABLES LIKE 'tmpdir';必须查,不能默认是/tmp
怎么快速释放临时空间并避免再报错
临时救急不是删日志或清 /tmp(MySQL 进程可能正用着),而是让当前查询绕过磁盘临时表 —— 强制走内存。
- 调高
sort_buffer_size和read_rnd_buffer_size(对单连接生效,别全局设太大) - 更关键的是:设
tmp_table_size和max_heap_table_size相等且足够大(例如256M),这样小一点的中间结果就能全程在内存里完成 - 立即生效命令:
SET SESSION tmp_table_size = 268435456;+SET SESSION max_heap_table_size = 268435456; - 注意:这个 session 级设置只管当前查询;如果应用是短连接,得在每次 query 前重设,或者改配置文件后重启
为什么改了 tmpdir 还是写到旧路径?
MySQL 启动后会锁定 tmpdir,运行中改 SET GLOBAL tmpdir = '/new/path' 是无效的 —— 这个变量根本不可动态修改。
- 必须停 MySQL,确认新路径存在、权限为
mysql:mysql、且有足够空间 - 修改配置文件(
my.cnf或mysqld.cnf)里的tmpdir = /mnt/mysql-tmp - 重启前检查:新路径不能是 NFS 或某些容器 overlayfs,MySQL 对 tmpdir 的 fs 类型敏感,ext4/xfs 最稳
- 重启后立刻验证:
SHOW VARIABLES LIKE 'tmpdir';,再ls -ld /mnt/mysql-tmp看权限
大查询本身能不能优化掉临时表依赖?
靠调参只是拖时间,真正治本是让 SQL 不生成巨型临时表。
- 加复合索引覆盖
ORDER BY和WHERE字段(例如WHERE status=1 ORDER BY created_at DESC→ 索引(status, created_at)) - 避免
SELECT *,只选需要字段,减少排序/分组的数据体积 -
LIMIT配合ORDER BY时,如果偏移很大(如LIMIT 1000000, 20),用游标分页(记录上一页最大 ID)替代 - 用
EXPLAIN FORMAT=TREE看执行计划里有没有Using temporary; Using filesort—— 这俩一起出现基本就是 error 28 的前兆
临时表空间问题从来不是孤立的磁盘告警,它背后大概率藏着没走索引的慢查询、不合理分页、或配置与负载严重不匹配。盯着 df 和 SHOW PROCESSLIST 一起看,比单纯扩容更有效。










