开启innodb_file_per_table后新表才生成独立.ibd文件,导出需flush tables加锁并同步导出ddl,导入须先建表、禁用约束、discard再import,且跨实例或版本不可直接拷贝.ibd。

innodb_file_per_table 开启后,表数据才可能单独导出
默认情况下 MySQL 的 InnoDB 表数据都存放在共享表空间 ibdata1 里,根本没法按表拆出文件。必须先开启 innodb_file_per_table,新创建或重建的表才会生成独立的 .ibd 文件。
注意:这个参数只影响后续操作,对已存在的表无效。即使开启了,老表仍留在 ibdata1 中,除非执行 ALTER TABLE ... ENGINE=InnoDB 重建。
- 动态开启(临时生效):
SET GLOBAL innodb_file_per_table = ON; - 永久生效:在
my.cnf或my.ini的[mysqld]段下添加innodb_file_per_table = ON,然后重启 MySQL - 验证是否生效:
SELECT @@innodb_file_per_table;返回1即成功
导出单个表的 .ibd 文件前必须停写并刷新脏页
直接复制 .ibd 文件是危险的——如果表正在被写入,文件内容可能不一致,后续导入会报错 Tablespace is missing for table xxx 或 Invalid or incomplete internal dictionary。
安全导出的前提是让该表进入“只读且干净”状态:
- 用
FLUSH TABLES tbl_name WITH READ LOCK;锁住表并刷出所有缓存页(注意:该命令会阻塞写入,但允许读) - 确认无活跃事务持有该表锁:
SHOW OPEN TABLES WHERE In_use > 0 AND Tables_in_db = 'your_db'; - 此时可安全复制
/var/lib/mysql/your_db/tbl_name.ibd(路径依实际 datadir 而定) - 导出完成后立刻解锁:
UNLOCK TABLES;
别跳过 FLUSH —— 即使表没被写,InnoDB 缓冲池里的脏页也可能没落盘。
导出的 .ibd 文件不能直接复用,需配套导出表结构
.ibd 文件只含数据和索引页,不含表定义、外键、字符集等元信息。单独拷贝过去再 CREATE TABLE 是行不通的。
必须同步获取建表语句:
- 用
SHOW CREATE TABLE tbl_name\G导出完整 DDL(注意保留ENGINE=InnoDB和ROW_FORMAT等细节) - 或用
mysqldump -d your_db tbl_name > tbl_name.sql(-d表示只导结构) - 若涉及外键,导出时要加
--skip-foreign-key-checks,否则导入可能失败
漏掉 ROW_FORMAT 或 KEY_BLOCK_SIZE 可能导致导入时报 Incorrect key file for table —— 因为 .ibd 文件内部格式和 DDL 声明不匹配。
导入 .ibd 文件需先建空表再替换,且必须禁用唯一检查
导入不是“放文件 + 启动就完事”,而是分三步走:
- 在目标库中执行建表语句(确保表名、字段、引擎、字符集、ROW_FORMAT 完全一致)
- 执行
ALTER TABLE tbl_name DISCARD TABLESPACE;删除当前.ibd(保留.frm或.sdi) - 把导出的
.ibd复制到对应数据库目录,再执行ALTER TABLE tbl_name IMPORT TABLESPACE;
关键点:
- 导入前必须设
SET FOREIGN_KEY_CHECKS = 0;和SET UNIQUE_CHECKS = 0;,否则IMPORT会校验约束并卡住 -
IMPORT成功后记得恢复:SET FOREIGN_KEY_CHECKS = 1;、SET UNIQUE_CHECKS = 1; - MySQL 5.7+ 要求
.ibd文件的 space ID 必须与数据字典一致,所以不能跨实例直接拷贝;8.0+ 更严格,还要求 server_uuid 匹配,否则报Space ID mismatch
真正麻烦的是跨版本或跨实例迁移——这时候 .ibd 文件基本不可直用,得靠 mysqldump 或 mysqlpump。











