IBD文件变大是MySQL 8.0默认行为叠加所致:ROW_FORMAT默认为DYNAMIC导致页分裂与溢出页堆积;长事务阻塞Undo清理使空间无法复用;OPTIMIZE TABLE不截断文件尾部空页;数据字典转InnoDB引发元数据膨胀。

ibd 文件变大,不是“MySQL 8.0 故意多占空间”,而是几个默认行为叠加的结果——你没改配置,它就按新规则干活,结果磁盘就涨了。
ROW_FORMAT 默认变成 DYNAMIC 了
MySQL 5.7 默认用COMPACT 行格式,8.0+ 新建表默认是 DYNAMIC。后者对 TEXT、VARCHAR 大字段更友好(外存存储),但会额外维护指针和空闲空间管理结构,单行开销略增;更重要的是,它更容易触发页分裂,尤其在主键非自增或频繁更新场景下,碎片率更高。
-
DYNAMIC表中每条含TEXT或长VARCHAR的记录,可能在页内只存 20 字节指针,真实数据甩到溢出页(off-page),而这些溢出页不参与页合并,长期积累就是额外空间 - 如果你用
mysqldump导入旧库,没显式指定ROW_FORMAT=COMPACT,新实例里重建的表就自动用DYNAMIC
长事务或未提交事务卡住 Undo 清理
哪怕你删光了数据,ibd 不缩容,背后常有 Undo 段被 hold 住:
- 执行过
INSERT INTO ... SELECT大表操作,但因max_binlog_cache_size或max_binlog_stmt_cache_size不足导致事务回滚——InnoDB 已分配空间,但回滚后不释放,ibd就“虚胖” - 存在未提交的事务(
SELECT ... FOR UPDATE、BEGIN后忘COMMIT),哪怕只查一行,也会阻止 purge 线程清理对应 Undo 记录,间接拖慢表空间复用
检查方法:
SELECT trx_id, trx_state, trx_started, trx_query FROM information_schema.INNODB_TRX ORDER BY trx_started LIMIT 5;重点关注
trx_state = 'RUNNING' 且 trx_started 时间异常早的记录。
OPTIMIZE TABLE 在 8.0 上不再“免费”
MySQL 8.0 默认启用innodb_strict_mode=ON,且 ALTER TABLE ... ENGINE=InnoDB(即 OPTIMIZE TABLE 底层动作)会强制重建聚簇索引,但:
- 它不会把空页从文件末尾截断,只是把有效数据紧凑排列,再写回原文件——所以
du -h table.ibd看不出变化 - 若表原来就在
ibdata1里(innodb_file_per_table=OFF),OPTIMIZE根本不生成新.ibd,徒劳无功 - 真正缩
ibd体积,得靠ALTER TABLE ... DISCARD TABLESPACE+IMPORT(需先FLUSH TABLES ... FOR EXPORT),但这要求表已启独立表空间且不能有外键依赖
别忽略隐藏的“元数据膨胀”
MySQL 8.0 的information_schema 和数据字典表(mysql.schemata、mysql.tables 等)全转成 InnoDB 引擎存储,还带事务支持。虽然单个表不大,但:
- 每次
CREATE/ALTER/DROP TABLE都写入数据字典事务日志,产生额外 Undo 和 Redo - 如果你高频建临时表、用
WITH语句嵌套多层 CTE,优化器生成的内部物化表也走 InnoDB,短命但积少成多
最直接的确认方式:
SELECT name, FILE_SIZE/1024/1024 AS MB FROM information_schema.INNODB_TABLESPACES WHERE name LIKE 'mysql/%' ORDER BY MB DESC LIMIT 5;
真正要压 ibd 大小,得盯住三件事:建表时锁死 ROW_FORMAT=COMPACT、关掉无关事务长期挂起、确保 innodb_file_per_table=ON 且老表已迁移。否则光清数据,文件体积纹丝不动。


















