必须开启innodb_file_per_table=on才能释放磁盘空间,否则drop/truncate表后ibdata1只增不减;唯一可信确认方式是执行show variables like 'innodb_file_per_table',返回on才生效,返回off则所有表仍写入共享表空间。

必须开启 innodb_file_per_table,否则 DROP TABLE 后磁盘空间永远不释放,ibdata1 只增不减。
怎么确认当前 MySQL 真的启用了独立表空间
别信“MySQL 5.6+ 默认开启”这种说法——它可能被配置覆盖或动态关掉。唯一可信方式是执行:
SHOW VARIABLES LIKE 'innodb_file_per_table';
返回 ON 才算生效;返回 OFF 表示所有新表仍写入 ibdata1,你在 datadir 下根本看不到任何 .ibd 文件。
Linux 下可辅助验证:ls -lh /var/lib/mysql/dbname/。如果只有 .frm(或 MySQL 8.0+ 的 .sdi)而没有 .ibd,基本可判定该库下表仍在共享空间。
为什么删了表,磁盘空间还是没回来
这是共享表空间最直接的代价:ibdata1 不会归还空间给操作系统。哪怕你 DROP TABLE 所有用户表,它的体积也纹丝不动——因为里面混存着数据字典、undo 日志段、回滚段、change buffer 等全局结构,这些内容随事务持续增长,且无法在线清理。
DROP TABLE 在共享模式下只是标记空间“可复用”,不是删除物理块;TRUNCATE TABLE 同样不收缩 ibdata1,性能优势也不存在。
启用 innodb_file_per_table=ON 后,DROP TABLE 会直接删除对应 .ibd 文件,磁盘空间立刻回收。
老表怎么从 ibdata1 搬到独立 .ibd
没有一键迁移命令。必须对每张存量表显式重建,才能把数据从 ibdata1 搬到独立 .ibd 文件中:
- 推荐语句:
ALTER TABLE table_name ENGINE=InnoDB或等价的OPTIMIZE TABLE table_name - 务必确认
innodb_file_per_table已为ON,否则重建完还是落回ibdata1 - 大表执行时间长,MySQL 5.6+ 虽支持 Online DDL,但仍会持有元数据锁(MDL),应用写入会阻塞
- 重建期间需双倍磁盘空间(旧
.ibd还没删,新文件已生成)
系统表(如 mysql.innodb_table_stats)强制驻留 ibdata1,不要碰。
真正缩小 ibdata1 的唯一办法
不能在线 shrink,也不能靠参数开关解决。如果 ibdata1 已膨胀到危险大小(比如 >100GB),唯一可靠路径是全库逻辑重建:
- 导出:
mysqldump -u root -p --all-databases --single-transaction --routines --triggers > full.sql - 停库,删掉
ibdata1、ib_logfile*、ibtmp1 - 配置文件明确写
innodb_file_per_table = ON - 重启后导入
full.sql
这个过程停机时间长,所以新实例上线前就该定好策略——别等 ibdata1 报警才想起查 innodb_file_per_table。











