mysql内存临时表上限由tmp_table_size与max_heap_table_size中较小值决定,必须设为相同值(如64m~256m)才能避免频繁落盘;同时需检查tmpdir、datadir及innodb_tmpdir所在分区空间与inode使用情况。

这不是业务表真满了,而是MySQL在某个环节卡住了内存或磁盘——必须立刻查tmp_table_size、max_heap_table_size、tmpdir和datadir四个地方。
查临时表内存上限是否被双参数掐死
MySQL用tmp_table_size和max_heap_table_size中较小的那个值,作为内存临时表的硬上限。只改一个等于白改。
- 执行
SHOW VARIABLES LIKE 'tmp_table_size';和SHOW VARIABLES LIKE 'max_heap_table_size';,确认两者是否一致 - 若不一致(比如
tmp_table_size = 256M但max_heap_table_size = 16M),那实际生效的就是16M,稍大点的GROUP BY或JOIN就会溢出落盘 - 会话级临时调高:运行
SET SESSION tmp_table_size = 268435456;和SET SESSION max_heap_table_size = 268435456;快速验证 - 永久生效需在
[mysqld]段配两行,单位只能是M或G(256MB或256m都无效)
确认tmpdir所在分区是否静默爆满
MySQL默认把排序、子查询、UNION等产生的临时文件写进/tmp,而这个路径常被其他进程(CI缓存、Tomcat日志)塞满,甚至挂了noexec导致根本写不进去。
- 先查当前路径:
SELECT @@tmpdir;,常见返回是/tmp或/var/tmp - 立刻执行
df -h /tmp和df -i /tmp——inode耗尽也会报“The table is full” - 清理命令:
find /tmp -name "*.tmp" -type f -mtime +7 -delete(慎用-delete前先-print预览) - 若
/tmp不可靠,可在配置里显式指定:tmpdir = /data/mysql_tmp,并确保该目录有读写+执行权限
盯紧datadir和innodb_tmpdir的真实使用率
报错时很多人只看df -h /,却漏掉datadir(如/var/lib/mysql)或innodb_tmpdir可能单独挂载在小分区上。
- 查路径:
SHOW VARIABLES LIKE 'datadir';、SHOW VARIABLES LIKE 'innodb_tmpdir'; - 对每个路径跑
df -h和df -i,特别注意ext4默认保留5%空间给root,普通用户进程可能“明明还有5%,却报No space left on device” - 若
df显示满但du -sh /var/lib/mysql总和远小于该值,大概率是已删未释放的句柄:lsof +L1 | grep mysql找出并重启对应进程 - 检查错误日志位置:
SHOW VARIABLES LIKE 'log_error';,然后tail -n 50 /var/log/mysql/error.log搜No space left on device或Could not create temporary file
别被业务表名误导,先确认引擎和错误触发点
报错里写的canteen_membership只是SQL执行到它时崩了,不是它本身占满空间。真正瓶颈往往藏在引擎行为和SQL写法里。
- 查引擎:
SELECT table_name, engine FROM information_schema.tables WHERE table_name = 'canteen_membership';,若是MEMORY引擎,才真是内存不够;若是InnoDB,就别急着扩表 - 监控指标:
SHOW GLOBAL STATUS LIKE 'Created_tmp%tables';,若Created_tmp_disk_tables持续上涨,说明临时表频繁落盘,直指tmp_table_size过低 - MyISAM表在磁盘满时会直接标为
crashed;InnoDB则倾向事务回滚或连接abort,但不会损坏元数据——所以看到Table is marked as crashed,基本可锁定是MyISAM + 磁盘问题 - 大表
TRUNCATE后.ibd文件大小不变是正常行为,真正收缩必须跟OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB
最容易被忽略的是:tmpdir和datadir可能分属不同挂载点,而运维习惯只盯后者;另外max_heap_table_size长期被当成“可选参数”,其实它和tmp_table_size是绑定生效的硬约束,少调一个就等于没调。











