“table space is full”指innodb表空间满,非磁盘满,需区分ibdata1(共享表空间,永不缩容)、ibtmp1(临时表空间,重启重置)或单个.ibd(独立表空间,索引设计不当易致膨胀)。

“Table space is full”不是磁盘满,而是InnoDB表空间写满了——最常见于ibdata1(共享表空间)撑爆,或ibtmp1(临时表空间)无法自动收缩。
查清到底是哪个表空间满了
先别急着扩容或删索引。MySQL里有多个“表空间”,报错时必须分清是哪一个:
-
ibdata1:共享表空间,存数据字典、undo日志、change buffer等——innodb_file_per_table=OFF时,所有表数据也挤在这儿;它永不自动缩容,删再多数据,文件大小也不变 -
ibtmp1:临时表空间,专供磁盘临时表(如大GROUP BY、UNION结果落盘);MySQL 8.0+默认自动扩展但不自动清理,重启才重置 -
.ibd文件:每个表的独立表空间(innodb_file_per_table=ON时存在);单个.ibd满,通常意味着该表本身数据/索引爆炸,或索引设计严重失当
快速定位命令:
SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, TOTAL_EXTENTS, DATA_FREE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'TABLESPACE' AND FILE_NAME LIKE '%ib%';
重点关注DATA_FREE为0、且FILE_NAME指向ibdata1或ibtmp1的行。
临时表空间ibtmp1爆满:重启最有效,但得先止损
ibtmp1满导致“Table is full”,往往发生在跑完一个大报表或ETL后没释放。它不像普通表能OPTIMIZE,也不能手动TRUNCATE。
- 临时方案:重启MySQL服务——
ibtmp1会在启动时重建,默认12M起,后续按需增长 - 长期方案:在
my.cnf中加两行,防它无节制膨胀:innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:2Ginnodb_temp_tablespaces_dir = /path/to/fast/disk/tmp/(把临时文件挪到空闲磁盘) - 别信“在线清理”:没有SQL命令能直接清空
ibtmp1;所谓“删除ibtmp1文件”必须停库,且风险极高
共享表空间ibdata1满了:不能删,只能迁或切模式
一旦ibdata1写满,ALTER TABLE ... ENGINE=InnoDB或OPTIMIZE TABLE都无效——它们只对独立表空间生效,对ibdata1只是内部整理页,不释放磁盘空间。
- 确认当前模式:
SHOW VARIABLES LIKE 'innodb_file_per_table';如果是OFF,说明所有表都挤在ibdata1里 - 迁移路径(必须停机):
① 备份全库(mysqldump --all-databases)
② 关库,删掉ibdata1、ib_logfile*(注意保留mysql系统库目录)
③ 开innodb_file_per_table=ON,再启库
④ 导入备份——此时每张表生成独立.ibd,ibdata1只存元数据,体积可控 - 若无法停机,唯一办法是扩容
ibdata1:修改my.cnf中innodb_data_file_path,例如从ibdata1:12M:autoextend改为ibdata1:12M;ibdata2:512M:autoextend,然后重启
独立表空间.ibd过大:索引才是真凶,不是数据量
看到某个.ibd文件特别大,第一反应不该是“删数据”,而是查索引是否失控。InnoDB二级索引会存储“索引列值 + 主键值”,如果在VARCHAR(2000)或TEXT字段上建了普通索引,一条索引记录可能占几KB,索引体积轻松超数据本身。
- 查冗余索引:
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA='your_db' AND TABLE_NAME='your_table' ORDER BY SEQ_IN_INDEX; - 删无效索引:
DROP INDEX idx_unneeded ON your_table;—— 尤其警惕那些只在WHERE里用过1次、或被更宽泛索引覆盖的索引 - 压缩表(读多写少场景):
ALTER TABLE your_table ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;,对日志类、归档类表可省40%~70%空间 - 别碰
OPTIMIZE TABLE除非刚删了>30%数据——它会锁表,且对小表收益极低
真正容易被忽略的点:ibdata1和ibtmp1的膨胀都是“静默发生”的,日常监控很少覆盖这两个文件;等报错才查,往往已卡在业务高峰。建议把ls -lh /var/lib/mysql/ib*加入每日巡检脚本。











