“The table is full”错误通常并非业务表真满,而是磁盘空间耗尽、内存临时表超限(tmp_table_size/max_heap_table_size不足)或MyISAM表达物理上限;需优先用df -h、SHOW TABLE STATUS、错误日志及lsof定位根因。

查清到底是哪张“表”满了
“Table is full”这个错误名有误导性——它不单指你 INSERT 的那张业务表真塞满了,更常指向临时表、内存表或磁盘空间耗尽。先别急着调配置,用这几步快速定位:
- 执行
SHOW TABLE STATUS LIKE 'your_table_name';,看Engine是InnoDB还是MyISAM,再核对Data_length和Max_data_length - 运行
df -h查系统磁盘剩余,尤其关注 MySQL 数据目录所在分区(比如/var/lib/mysql) - 检查 MySQL 错误日志:
tail -n 50 /var/log/mysql/error.log,重点找disk space、no space left on device或tmp table size exceeded类提示
tmp_table_size 和 max_heap_table_size 不是万能解药
这两个参数只影响内存中临时表的上限,当查询(如 GROUP BY、ORDER BY、子查询)需要建临时表时才生效。盲目调高反而可能触发 OOM —— 它们共享同一块内存池,且 max_heap_table_size 还限制 MEMORY 引擎表大小。
- 确认是否真由临时表触发:在会话中执行
SELECT @@tmp_table_size, @@max_heap_table_size;,再跑出错 SQL 前加EXPLAIN FORMAT=TRADITIONAL,看是否有Using temporary - 安全调整建议:两者设为相等,例如
256M,但总和不应超过物理内存的 10%~15%,避免挤占 InnoDB buffer pool - 改完必须重启 MySQL 生效(
tmp_table_size是动态变量,但实际效果依赖会话重连;而max_heap_table_size在线改仅对新连接有效)
磁盘空间满才是最常见原因
80% 以上的 “Table is full” 实际是磁盘写满,尤其是 ibdata1(共享表空间)或 .ibd 文件持续增长撑爆分区。注意几个隐蔽点:
-
df -h显示满,但du -sh /var/lib/mysql总和远小于磁盘容量?大概率是被删除却未释放的文件(lsof | grep deleted找出 mysqld 持有的已删日志或 binlog) - MySQL 的
slow_query_log或general_log被 vim 编辑后保存,会导致 mysqld 继续往旧文件句柄写入,文件不显示在目录里却持续占空间 - InnoDB 的
innodb_file_per_table=OFF时,所有表数据都挤在ibdata1里,删数据不缩容,只能导出重建
真正有效的扩容路径
别只盯着参数,按优先级操作:
- 立刻释放空间:执行
FLUSH LOGS;清空当前 slow/general log;用PURGE BINARY LOGS BEFORE '2026-04-01';清理过期 binlog - 检查大表:用
SELECT table_schema, table_name, round(((data_length + index_length) / 1024 / 1024), 2) size_mb FROM information_schema.TABLES ORDER BY size_mb DESC LIMIT 10;找出前 10 大表,确认是否可归档或分区 - 若确定是
ibdata1膨胀:停库 → mysqldump 全量导出 → 删除ibdata1和ib_logfile*→ 修改配置启用innodb_file_per_table=ON→ 重启 → 导入 - 长期预防:监控
df和information_schema.INNODB_SYS_TABLESPACES,设置自动清理 binlog(binlog_expire_logs_seconds = 2592000)
真正麻烦的不是调参,而是没分清“表空间满”“磁盘满”“临时表内存满”这三类根本不同的问题。一个 df -h 和一条 SHOW ENGINE INNODB STATUS\G 里的 FILE I/O 段,往往比改十次配置都管用。


















