1. 概述:可传输表空间

在 InnoDB 且 innodb_file_per_table=ON(MySQL 5.6.6 起默认开启)时,每张表的数据独立存储于一个 .ibd 文件。MySQL 提供了一对 DDL 语句,允许在表定义(数据字典元数据)磁盘上的 .ibd 文件之间建立或解除关联:

  • ALTER TABLE tbl DISCARD TABLESPACE:解除当前表与 .ibd 的关联,并物理删除该文件。表结构仍保留在数据字典,但无任何数据文件。
  • ALTER TABLE tbl IMPORT TABLESPACE:在表定义已存在的前提下,将一份外部 .ibd 文件挂接到该表,InnoDB 完成内部一致性校验。

二者组合形成**可传输表空间(Transportable Tablespaces)**机制,典型用途:替换损坏的 .ibd 文件、跨实例搬运表数据、利用物理备份快速恢复单表。

版本说明:MySQL 5.6 起逐步完善,MySQL 8.0 引入 SDI(Serialized Dictionary Information)嵌入 .ibd,元数据校验方式有所演进。


2. 标准操作流程

2.1 源端:导出一致性快照

1
FLUSH TABLES tbl FOR EXPORT;

执行效果:将 buffer pool 中该表的脏页全部刷入 .ibd,使文件处于可安全拷贝的一致状态;MySQL 5.6/5.7 同时生成 .cfg 文件用于目标端校验;MySQL 8.0 中 .ibd 内已嵌入 SDI。

在持锁期间复制文件(保持当前会话不关闭):

1
2
cp /var/lib/mysql/db_name/tbl.ibd  /backup/
cp /var/lib/mysql/db_name/tbl.cfg  /backup/

复制完成后解锁:UNLOCK TABLES;

FLUSH TABLES FOR EXPORT 持有共享元数据锁(MDL),期间该表可读不可写,应在业务低峰或维护窗口执行。

2.2 目标端:建壳 -> 丢弃 -> 替换 -> 导入

1
2
CREATE TABLE tbl ( ... ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC ...;
ALTER TABLE tbl DISCARD TABLESPACE;
1
2
3
cp /backup/tbl.ibd  /var/lib/mysql/db_name/
cp /backup/tbl.cfg  /var/lib/mysql/db_name/
chown mysql:mysql /var/lib/mysql/db_name/tbl.*
1
ALTER TABLE tbl IMPORT TABLESPACE;

IMPORT 阶段 InnoDB 会校验 space id、页格式、SDI/.cfg 中的表定义,任何不匹配均报错并拒绝导入。

3. 四个典型场景

场景一:.ibd 文件损坏

适用条件:存在一份物理完好的替代 .ibd(来自物理备份、备库、同结构表副本等)。

常见误解:认为对"已损坏且无第二份文件"的 .ibd 执行 IMPORT 可以修复它。实际上若页链、B+ 树节点或字典信息已物理损坏,导入大概率失败;即使勉强挂载数据也不可信。

建议操作路径

  1. 查阅 MySQL 错误日志,评估损坏范围
  2. 若有干净备份:执行 DISCARD -> 拷入备份 .ibd -> IMPORT
  3. 核查一致性前提:
    • 源与目标的 innodb_page_size 必须相同(实例级参数,不可在线修改)
    • ROW_FORMAT 必须一致
    • MySQL 8.0 中若表经历过 INSTANT ADD COLUMN,ibd 内嵌的 instant 列元数据必须与目标表完全匹配

补充:字典引用丢失时可通过"按原 DDL 建空表 + DISCARD + 拷入正确 .ibd + IMPORT"挂接,属高风险,务必先在隔离环境演练验证。


场景二:跨实例迁移数据

官方最主要设计用途:避免逻辑导入(解析 SQL + 行重插入)的时间开销,直接搬运物理文件,适合数百 GB 级大表迁移。

必须严格一致的要点:表 DDL 等价(列定义、顺序、类型、字符集、索引结构)、innodb_page_size 相同(常见 16KB)、ROW_FORMAT 一致(DYNAMIC/COMPACT 等)、含外键表需先处理外键、分区表需按分区逐一操作、全文和空间索引部分版本有限制。

运维注意事项:大表在 FLUSH TABLES FOR EXPORT 持锁期间不可写,务必在维护窗口执行。若目标为主从架构,IMPORT 会写入 binlog 并在从库重放,需结合 sql_log_bin=0 评估复制一致性影响。

场景三:误删除大表的恢复

情形 A:误删 .ibd 文件,表定义仍在

1
2
3
4
-- 此时查表报 Tablespace is missing 类错误
ALTER TABLE tbl DISCARD TABLESPACE;
-- 拷入备份中同版本、同 DDL 的 .ibd 后执行:
ALTER TABLE tbl IMPORT TABLESPACE;

情形 B:执行了 DROP TABLE

DROP TABLE 会将表定义从数据字典中彻底移除,.ibd 同时被删除,此时没有空壳可供挂接,DISCARD/IMPORT 无法直接使用

正确恢复路径(按优先级):

  1. 延迟从库:在 DDL 传播到从库前及时停止复制并提取数据
  2. binlog PITR:结合全量备份 + mysqlbinlog 重放至误操作时间点之前
  3. 物理备份隔离恢复:将 XtraBackup 备份恢复至隔离实例,再逻辑导出目标表

DISCARD/IMPORT 在此场景中是有可用 .ibd 副本时的加速工具,不是替代备份体系的万能修复方案。


场景四:表空间 ID 冲突

现象:IMPORT TABLESPACE 时报 space id 冲突:

InnoDB: tablespace id in file '...' is X, but in the InnoDB data dictionary it is Y

根因:每个 InnoDB 表空间都有内部 space id,同时记录在 .ibd 文件头和数据字典中,若二者不一致 InnoDB 会拒绝挂接。

正确处理方式

  1. 使用完整官方流程(FLUSH FOR EXPORT -> 拷贝 ibd+cfg -> CREATE TABLE -> DISCARD -> 放文件 -> IMPORT),InnoDB 在 IMPORT 阶段依据字典重新分配正确的 space id。
  2. 确保目标表是新建后再 DISCARD,IMPORT 时 InnoDB 会将 ibd 内的 space id 更新为字典值,而非沿用源端的 id。
  3. 严禁手动修改 ibd 二进制头中的 space id:无官方支持,极易引入不可见的物理损坏,不应作为生产修复手段。

4. 限制与风险清单

限制项说明
外键含外键表导入需 SET foreign_key_checks=0 或临时移除外键
分区表支持,但需按分区逐一操作,流程复杂
全文索引部分版本不支持,需查手册确认
空间索引同全文索引,存在版本限制
INSTANT ADD COLUMN(8.0)instant 列元数据历史必须完全一致,否则 SDI 校验失败
innodb_page_size实例级参数,源与目标必须相同,不可在线变更
文件属主与权限ibd 属主必须为 MySQL 进程用户(如 mysql:mysql)
从库操作在复制从库上执行可能破坏主从一致性,默认不推荐
安全合规DISCARD 删除文件非安全擦除,合规场景需在存储层另行处理

5. 与其他方案的横向对比

方案适用规模优势局限
DISCARD / IMPORT单表 GB-TB 级省去重解析与重插入,速度快DDL 页大小元数据必须严格匹配
mysqldump 逻辑导出中小表跨版本场景兼容性最佳可跨大版本时间与磁盘开销大
mydumper / myloader中大表多线程并行速度优于 mysqldump仍属逻辑层有行重插入开销
XtraBackup 物理备份整实例或多表热备一致性好可用于 PITR工具链要求高恢复颗粒度为实例级
延迟从库防误操作 DR实时同步可秒级介入需提前规划有额外存储成本

6. 小结

DISCARD TABLESPACE 与 IMPORT TABLESPACE 的本质是:在表定义已存在的前提下,对 InnoDB 独立表空间文件进行物理替换。适合大表快速迁移与定向恢复。

成功使用该机制的核心前提:

  1. 有一份物理完好的 ibd 副本
  2. 源端与目标端的 innodb_page_sizeROW_FORMAT、表 DDL 严格一致
  3. 按照官方完整流程执行(FLUSH FOR EXPORT -> 拷贝 -> DISCARD -> 放文件 -> IMPORT),不走捷径

对于无备份的损坏、已 DROP 的表,应优先走备份 + binlog PITR 的正统恢复路径,将可传输表空间作为条件具备时的加速工具,而非替代数据保护体系的万能修复手段。