必须手动验证 innodb_file_per_table 是否开启:执行 SHOW VARIABLES LIKE 'innodb_file_per_table',仅当返回 ON 才生效;OFF 时新表仍写入 ibdata1,无 .ibd 文件,且已有表无法自动迁移;DROP/TRUNCATE 表仅在 ON 时释放磁盘空间;ibdata1 膨胀后无法在线收缩,唯一缩容方式是全库逻辑重建。

确认 innodb_file_per_table 是否真开启
别信“MySQL 8.0 默认开启”这种说法——必须亲自查。执行 SHOW VARIABLES LIKE 'innodb_file_per_table';,只看返回值是不是 ON。返回 OFF 意味着所有新表仍写进 ibdata1,你根本看不到 .ibd 文件,也别谈维护优势。
动态设置 SET GLOBAL innodb_file_per_table = ON; 是允许的,但只影响后续新建的表;已有表不会自动搬出 ibdata1,哪怕你重启、OPTIMIZE TABLE 或 ALTER TABLE ... ENGINE=InnoDB,只要建表时该变量是 OFF,数据就锁死在共享空间里。
DROP / TRUNCATE 后磁盘空间是否真正回收
这是最直接的维护分水岭:
- 共享表空间(
innodb_file_per_table = OFF):执行DROP TABLE或TRUNCATE TABLE后,ibdata1文件体积纹丝不动,操作系统看不到空间释放 - 独立表空间(
ON):DROP TABLE会立刻删除对应table_name.ibd文件,磁盘空间秒级回收 - 若只是大量
DELETE而不想删表,可用ALTER TABLE t ENGINE=InnoDB;重建表来收缩.ibd—— 注意需双倍临时磁盘空间,且大表会锁表
单表迁移、误恢复、备份粒度是否可控
独立表空间让物理文件和逻辑表一一对应,实操中省掉很多“只能全库导出”的妥协:
- 快速拷贝某张大表到另一实例:
cp /var/lib/mysql/dbname/t1.ibd+FLUSH TABLES WITH READ LOCK+IMPORT TABLESPACE(需严格匹配表结构、checksum、server_uuid) - 误删表但还留着
.ibd和.sdi(MySQL 5.7+)?比从膨胀的ibdata1里抢救现实得多 - 分区表每个分区生成独立
.ibd,归档或迁移可按分区操作,不用动整张表 - 用
du -sh /var/lib/mysql/dbname/*.ibd直接观察每张表磁盘占用,无需查INFORMATION_SCHEMA或估算
ibdata1 膨胀后能否在线收缩
不能。这是共享表空间最致命的运维硬伤:
ibdata1 不仅存用户数据,还混着数据字典、undo 日志段、回滚段、change buffer 等全局结构,这些内容随事务持续增长,且无法在线清理。哪怕你 DROP 所有用户表,ibdata1 也不会缩小。
真正缩小它的唯一路径是全库逻辑重建:mysqldump --all-databases → 停库 → 删除 ibdata1、ib_logfile*、ibtmp1 → 配置明确启用 innodb_file_per_table=1 → 导入。整个过程停机时间长,风险高。
所以“要不要开启”不是上线后才考虑的问题,而是新实例部署前就必须定死的策略。一旦 ibdata1 胀到上百 GB,再想切回来,代价远超预防成本。











