#### 15.6.1.3 导入 InnoDB 表

[](<>)[](<>)[](<>)

本节介绍如何使用*可传输表空间*功能，它允许导入驻留在 file-per-table 表空间中的表、分区表或单个表分区。您可能想要导入表的原因有很多：

-   在非生产 MySQL 服务器实例上运行报告以避免在生产服务器上增加额外负载。

-   将数据复制到新的副本服务器。

-   从备份的表空间文件中恢复表。

-   作为一种比导入转储文件更快的移动数据方式，这需要重新插入数据和重建索引。

-   将数据移动到具有更适合您的存储要求的存储介质的服务器。例如，您可以将繁忙的表移至 SSD 设备，或将大型表移至大容量 HDD 设备。

    这*可传输表空间*本节中的以下主题下描述了该功能：

-   [先决条件](innodb-table-import.html#innodb-table-import-prerequsites)

-   [导入表](innodb-table-import.html#innodb-table-import-example)

-   [导入分区表](innodb-table-import.html#innodb-table-import-partitioned-table)

-   [导入表分区](innodb-table-import.html#innodb-table-import-partitions)

-   [限制](innodb-table-import.html#innodb-table-import-limitations)

-   [使用说明](innodb-table-import.html#innodb-table-import-usage-notes)

-   [内件](innodb-table-import.html#innodb-table-import-internals)

##### 先决条件

-   这[`innodb_file_per_table`](innodb-parameters.html#sysvar_innodb_file_per_table)变量必须启用，默认情况下是启用的。

-   表空间的页面大小必须与目标 MySQL 服务器实例的页面大小相匹配。`InnoDB`页面大小由[`innodb_page_size`](innodb-parameters.html#sysvar_innodb_page_size)变量，在初始化 MySQL 服务器实例时配置。

-   如果表有外键关系，[`foreign_key_checks`](server-system-variables.html#sysvar_foreign_key_checks)执行前必须禁用`丢弃表空间`.此外，您应该在同一逻辑时间点导出所有与外键相关的表，如[`ALTER TABLE ... 导入表空间`](alter-table.html)不对导入的数据强制执行外键约束。为此，请停止更新相关表，提交所有事务，获取表上的共享锁，然后执行导出操作。

-   从另一个 MySQL 服务器实例导入表时，两个 MySQL 服务器实例必须具有通用可用性 (GA) 状态并且必须是相同的版本。否则，表必须在导入它的同一个 MySQL 服务器实例上创建。

-   如果表是通过指定在外部目录中创建的`数据目录`条款中的[`创建表`](create-table.html)语句，您在目标实例上替换的表必须使用相同的定义`数据目录`条款。如果子句不匹配，则会报告架构不匹配错误。确定源表是否使用`数据目录`子句，使用[`显示创建表`](show-create-table.html)查看表定义。有关使用`数据目录`子句，见[第 15.6.1.2 节，“在外部创建表”](innodb-create-table-external.html).

-   如果一个`ROW_FORMAT`选项未在表定义中明确定义或`ROW_FORMAT=默认`被使用时，[`innodb_default_row_format`](innodb-parameters.html#sysvar_innodb_default_row_format)源实例和目标实例上的设置必须相同。否则，尝试导入操作时会报告架构不匹配错误。采用[`显示创建表`](show-create-table.html)检查表定义。采用[`显示变量`](show-variables.html)检查[`innodb_default_row_format`](innodb-parameters.html#sysvar_innodb_default_row_format)环境。有关相关信息，请参阅[定义表格的行格式](innodb-row-format.html#innodb-row-format-defining).

##### 导入表

此示例演示如何导入驻留在 file-per-table 表空间中的常规非分区表。

1.  在目标实例上，创建一个与您要导入的表具有相同定义的表。（您可以使用获取表定义[`显示创建表`](show-create-table.html)语法。）如果表定义不匹配，当您尝试导入操作时会报告架构不匹配错误。

    ```
    mysql> USE test;
    mysql> CREATE TABLE t1 (c1 INT) ENGINE=INNODB;
    ```

2.  在目标实例上，丢弃刚刚创建的表的表空间。（导入前必须丢弃接收表的表空间。）

    ```
    mysql> ALTER TABLE t1 DISCARD TABLESPACE;
    ```

3.  在源实例上，运行[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)静默您要导入的表。当表被停顿时，表上只允许只读事务。

    ```
    mysql> USE test;
    mysql> FLUSH TABLES t1 FOR EXPORT;
    ```

    [`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)确保对命名表的更改刷新到磁盘，以便在服务器运行时可以制作二进制表副本。什么时候[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)正在运行，`InnoDB`生成一个`.cfg`表的模式目录中的元数据文件。这`.cfg`文件包含在导入操作期间用于模式验证的元数据。

    笔记

    正在执行的连接[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)在操作运行时必须保持打开状态；否则，`.cfg`文件被删除，因为锁在连接关闭时被释放。

4.  复制`.ibd`文件和`.cfg`从源实例到目标实例的元数据文件。例如：

    ```
    $> scp /path/to/datadir/test/t1.{ibd,cfg} destination-server:/path/to/datadir/test
    ```

    这`.ibd`文件和`.cfg`必须在释放共享锁之前复制文件，如下一步所述。

    笔记

    如果要从加密表空间导入表，`InnoDB`生成一个`.cfp`除了一个文件`.cfg`元数据文件。这`.cfp`文件必须与`.cfg`文件。这`.cfp`文件包含一个传输密钥和一个加密的表空间密钥。进口时，`InnoDB`使用传输密钥解密表空间密钥。有关相关信息，请参阅[第 15.13 节，“InnoDB 静态数据加密”](innodb-data-encryption.html).

5.  在源实例上，使用[`解锁桌子`](lock-tables.html)释放由[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)陈述：

    ```
    mysql> USE test;
    mysql> UNLOCK TABLES;
    ```

    这[`解锁桌子`](lock-tables.html)操作还删除了`.cfg`文件。

6.  在目标实例上，导入表空间：

    ```
    mysql> USE test;
    mysql> ALTER TABLE t1 IMPORT TABLESPACE;
    ```

##### 导入分区表

此示例演示如何导入分区表，其中每个表分区驻留在每个表的文件表空间中。

1.  在目标实例上，创建一个与要导入的分区表具有相同定义的分区表。（您可以使用获取表定义[`显示创建表`](show-create-table.html)语法。）如果表定义不匹配，当您尝试导入操作时会报告架构不匹配错误。

    ```
    mysql> USE test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 3;
    ```

    在里面`/*`数据目录`*/测试`目录，有一个表空间`.ibd`三个分区中的每个分区的文件。

    ```
    mysql> \! ls /path/to/datadir/test/
    t1#p#p0.ibd  t1#p#p1.ibd  t1#p#p2.ibd
    ```

2.  在目标实例上，丢弃分区表的表空间。（在导入操作之前，必须丢弃接收表的表空间。）

    ```
    mysql> ALTER TABLE t1 DISCARD TABLESPACE;
    ```

    三个表空间`.ibd`分区表的文件从`/*`数据目录`*/测试`目录。

3.  在源实例上，运行[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)静默您打算导入的分区表。当表被停顿时，表上只允许只读事务。

    ```
    mysql> USE test;
    mysql> FLUSH TABLES t1 FOR EXPORT;
    ```

    [`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)确保对命名表的更改刷新到磁盘，以便在服务器运行时可以进行二进制表副本。什么时候[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)正在运行，`InnoDB`生成`.cfg`表的每个表空间文件的表模式目录中的元数据文件。

    ```
    mysql> \! ls /path/to/datadir/test/
    t1#p#p0.ibd  t1#p#p1.ibd  t1#p#p2.ibd
    t1#p#p0.cfg  t1#p#p1.cfg  t1#p#p2.cfg
    ```

    这`.cfg`文件包含导入表空间时用于模式验证的元数据。[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)只能在表上运行，不能在单个表分区上运行。

4.  复制`.ibd`和`.cfg`文件从源实例模式目录到目标实例模式目录。例如：

    ```
    $>scp /path/to/datadir/test/t1*.{ibd,cfg} destination-server:/path/to/datadir/test
    ```

    这`.ibd`和`.cfg`必须在释放共享锁之前复制文件，如下一步所述。

    笔记

    如果要从加密表空间导入表，`InnoDB`生成一个`.cfp`除了一个文件`.cfg`元数据文件。这`.cfp`文件必须与`.cfg`文件。这`.cfp`文件包含传输密钥和加密的表空间密钥。进口时，`InnoDB`使用传输密钥解密表空间密钥。有关相关信息，请参阅[第 15.13 节，“InnoDB 静态数据加密”](innodb-data-encryption.html).

5.  在源实例上，使用[`解锁桌子`](lock-tables.html)释放获得的锁[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)：

    ```
    mysql> USE test;
    mysql> UNLOCK TABLES;
    ```

6.  在目标实例上，导入分区表的表空间：

    ```
    mysql> USE test;
    mysql> ALTER TABLE t1 IMPORT TABLESPACE;
    ```

##### 导入表分区

此示例演示如何导入单个表分区，其中每个分区驻留在一个 file-per-table 表空间文件中。

在以下示例中，两个分区 (`p2`和`p3`) 的一个四分区表被导入。

1.  在目标实例上，创建一个与要从中导入分区的分区表具有相同定义的分区表。（您可以使用获取表定义[`显示创建表`](show-create-table.html)语法。）如果表定义不匹配，当您尝试导入操作时会报告架构不匹配错误。

    ```
    mysql> USE test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 4;
    ```

    在里面`/*`数据目录`*/测试`目录，有一个表空间`.ibd`四个分区中的每个分区的文件。

    ```
    mysql> \! ls /path/to/datadir/test/
    t1#p#p0.ibd  t1#p#p1.ibd  t1#p#p2.ibd t1#p#p3.ibd
    ```

2.  在目标实例上，丢弃您打算从源实例导入的分区。（在导入分区之前，您必须从接收分区表中丢弃相应的分区。）

    ```
    mysql> ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;
    ```

    表空间`.ibd`两个废弃分区的文件将从`/*`数据目录`*/测试`目标实例上的目录，留下以下文件：

    ```
    mysql> \! ls /path/to/datadir/test/
    t1#p#p0.ibd  t1#p#p1.ibd
    ```

    笔记

    什么时候[`ALTER TABLE ... 丢弃分区 ... TABLESPACE`](alter-table.html)在子分区表上运行，允许分区和子分区表名称。指定分区名称时，该分区的子分区将包含在操作中。

3.  在源实例上，运行[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)静默分区表。当表被停顿时，表上只允许只读事务。

    ```
    mysql> USE test;
    mysql> FLUSH TABLES t1 FOR EXPORT;
    ```

    [`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)确保对命名表的更改刷新到磁盘，以便在实例运行时可以进行二进制表副本。什么时候[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)正在运行，`InnoDB`生成一个`.cfg`表的模式目录中每个表的表空间文件的元数据文件。

    ```
    mysql> \! ls /path/to/datadir/test/
    t1#p#p0.ibd  t1#p#p1.ibd  t1#p#p2.ibd t1#p#p3.ibd
    t1#p#p0.cfg  t1#p#p1.cfg  t1#p#p2.cfg t1#p#p3.cfg
    ```

    这`.cfg`文件包含在导入操作期间用于模式验证的元数据。[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)只能在表上运行，不能在单个表分区上运行。

4.  复制`.ibd`和`.cfg`分区文件`p2`和分区`p3`从源实例架构目录到目标实例架构目录。

    ```
    $> scp t1#p#p2.ibd t1#p#p2.cfg t1#p#p3.ibd t1#p#p3.cfg destination-server:/path/to/datadir/test
    ```

    这`.ibd`和`.cfg`必须在释放共享锁之前复制文件，如下一步所述。

    笔记

    如果要从加密表空间导入分区，`InnoDB`生成一个`.cfp`除了一个文件`.cfg`元数据文件。这`.cfp`文件必须与`.cfg`文件。这`.cfp`文件包含传输密钥和加密的表空间密钥。进口时，`InnoDB`使用传输密钥解密表空间密钥。有关相关信息，请参阅[第 15.13 节，“InnoDB 静态数据加密”](innodb-data-encryption.html).

5.  在源实例上，使用[`解锁桌子`](lock-tables.html)释放获得的锁[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)：

    ```
    mysql> USE test;
    mysql> UNLOCK TABLES;
    ```

6.  在目标实例上，导入表分区`p2`和`p3`：

    ```
    mysql> USE test;
    mysql> ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;
    ```

    笔记

    什么时候[`ALTER TABLE ... 导入分区 ... TABLESPACE`](alter-table.html)在子分区表上运行，允许分区和子分区表名称。指定分区名称时，该分区的子分区将包含在操作中。

##### 限制

-   这*可传输表空间*仅驻留在 file-per-table 表空间中的表支持该功能。驻留在系统表空间或通用表空间中的表不支持它。共享表空间中的表不能被停顿。

-   [`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)在带有 a 的表上不受支持`全文`索引，因为不能刷新全文搜索辅助表。导入带有 a 的表后`全文`索引，运行[`优化表`](optimize-table.html)重建`全文`索引。或者，放下`全文`导出操作之前的索引，并在目标实例上导入表后重新创建索引。

-   由于一个`.cfg`元数据文件限制，导入分区表时不会报告分区类型或分区定义差异的架构不匹配。报告列差异。

-   在 MySQL 8.0.19 之前，索引键部分排序顺序信息不存储到`.cfg`表空间导入操作期间使用的元数据文件。因此，索引键部分的排序顺序被假定为升序，这是默认值。因此，如果导入操作中涉及的一个表是使用 DESC 索引键部分排序顺序定义的，而另一个表没有定义，则记录可能会以意外的顺序排序。解决方法是删除并重新创建受影响的索引。有关索引键部分排序顺序的信息，请参阅[第 13.1.15 节，“CREATE INDEX 语句”](create-index.html).

    这`.cfg`文件格式在 MySQL 8.0.19 中更新，包括索引键部分排序信息。上述问题不影响 MySQL 8.0.19 服务器实例或更高版本之间的导入操作。

##### 使用说明

-   [`ALTER TABLE ... 导入表空间`](alter-table.html)不需要`.cfg`元数据文件以导入表。但是，在导入时不执行元数据检查`.cfg`文件，并发出类似于以下的警告：

    ```
    Message: InnoDB: IO Read error: (2, No such file or directory) Error opening '.\
    test\t.cfg', will attempt to import without schema verification
    1 row in set (0.00 sec)
    ```

    导入没有表的表`.cfg`元数据文件应该只在没有模式不匹配的情况下才被考虑。无需文件即可导入`.cfg`文件在无法访问元数据的崩溃恢复场景中可能很有用。

-   在 Windows 上，`InnoDB`在内部以小写形式存储数据库、表空间和表名。为避免在 Linux 和 Unix 等区分大小写的操作系统上出现导入问题，请使用小写名称创建所有数据库、表空间和表。确保名称以小写形式创建的一种便捷方法是设置[`lower_case_table_names`](server-system-variables.html#sysvar_lower_case_table_names)在初始化服务器之前设置为 1。（禁止以[`lower_case_table_names`](server-system-variables.html#sysvar_lower_case_table_names)与初始化服务器时使用的设置不同的设置。）

    ```
    [mysqld]
    lower_case_table_names=1
    ```

-   跑步时[`ALTER TABLE ... 丢弃分区 ... TABLESPACE`](alter-table.html)和[`ALTER TABLE ... 导入分区 ... TABLESPACE`](alter-table.html)在子分区表上，允许分区和子分区表名称。指定分区名称时，该分区的子分区将包含在操作中。

##### 内件

以下信息描述了在表导入过程中写入错误日志的内部信息和消息。

什么时候[`ALTER TABLE ... 丢弃表空间`](alter-table.html)在目标实例上运行：

-   表被锁定在 X 模式。

-   表空间与表分离。

    什么时候[`冲洗表...用于出口`](flush.html#flush-tables-for-export-with-list)在源实例上运行：

-   为导出而刷新的表被锁定在共享模式。

-   清除协调器线程已停止。

-   脏页同步到磁盘。

-   表元数据写入二进制文件`.cfg`文件。

    此操作的预期错误日志消息：


```
[Note] InnoDB: Sync to disk of '"test"."t1"' started.
[Note] InnoDB: Stopping purge
[Note] InnoDB: Writing table metadata to './test/t1.cfg'
[Note] InnoDB: Table '"test"."t1"' flushed to disk
```

什么时候[`解锁桌子`](lock-tables.html)在源实例上运行：

-   二进制`.cfg`文件被删除。

-   正在导入的一个或多个表上的共享锁被释放并重新启动清除协调器线程。

    此操作的预期错误日志消息：


```
[Note] InnoDB: Deleting the meta-data file './test/t1.cfg'
[Note] InnoDB: Resuming purge
```

什么时候[`ALTER TABLE ... 导入表空间`](alter-table.html)在目标实例上运行时，导入算法对正在导入的每个表空间执行以下操作：

-   检查每个表空间页面是否损坏。

-   每个页面上的空间 ID 和日志序列号 (LSN) 都会更新。

-   为标题页验证标志并更新 LSN。

-   Btree 页面已更新。

-   页面状态设置为脏，以便将其写入磁盘。

    此操作的预期错误日志消息：


```
[Note] InnoDB: Importing tablespace for table 'test/t1' that was exported
from host 'host_name'
[Note] InnoDB: Phase I - Update all pages
[Note] InnoDB: Sync to disk
[Note] InnoDB: Sync to disk - done!
[Note] InnoDB: Phase III - Flush changes to disk
[Note] InnoDB: Phase IV - Flush complete
```

笔记

您还可能会收到一个表空间被丢弃的警告（如果您丢弃了目标表的表空间）和一条消息，指出由于丢失而无法计算统计信息`.ibd`文件：

```
[Warning] InnoDB: Table "test"."t1" tablespace is set as discarded.
7f34d9a37700 InnoDB: cannot calculate statistics for table
"test"."t1" because the .ibd file is missing. For help, please refer to
http://dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting.html
```
