概述

复制表空间文件(.ibd文件) 是移动数据的最快方式, 比通过mysqldump或mydumper导出和导入数据还快。
移动以后数据是立即可用的, 而不必重新插入和重建索引。

有很多原因可以解释为什么需要将一个InnoDB文件/表空间复制到一个不同的实例:
1.为了运行报表而不会给生产服务器增加额外的负载
2.为了在新的从服务器上为一个表设置相同的数据。
3.为了在出现问题或错误后恢复备份的表或分区。
4.为了把繁忙的表放在SSD设备上, 或在大容量的HDD设备上建大型表

大致步骤

(1)在目标库上创建表,并使用相同的表定义,并在目标库上执行DISCARD TABLESPACE命令。
(2)在源库上执行FLUSH TABLES FOR EXPORT, 这将确保对指定表的更改被刷新到磁盘,因此可以在运行实例时生成二进制表的副本。在执行该语句之后, 表被锁定, 并且不接受任何写入操作; 当然, 可以进行读操作。
(3)你可以将该表的.ibd文件复制到目标库, 在源库上执行UNLOCK, 最后执行IMPORT TABLESPACE命令, 该命令接受复制的.ibd文件。

建立测试数据

例如,你希望将测试数据库的events_history表从一个服务器(源库) 复制到另一个服务器(目标库)中
如果没有event_history的话, 就先创建这个表, 并且插入一些行以便演示

mysql>USE test;

mysql>CREATE TABLE IF NOT EXISTS `event_history`(
`event_id` int(11) NOT NULL,
`event_name` varchar(10) DEFAULT NULL,
`created_at` datetime NOT NULL,
`last_updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
`event_type` varchar(10) NOT NULL,
`msg` tinytext NOT NULL,
PRIMARY KEY(`eventid`,`created_at`)
) ENGINE=InnoDBD EFAULT CHARSET=utf8mb4
PARTITION BY RANGE (to days(`created at`))
(PARTITION 2017_oct_week VALUES LESS THAN(736974) ENGINE = InnoDB,
PARTITION p20171008 VALUES LESS THAN(736975) ENGINE = InnoDB,
PARTITION p20171009 VALUES LESS THAN(736976) ENGINE = InnoDB,
PARTITION p20171010 VALUES LESS THAN(736977) ENGINE = InnoDB,
PARTITION p20171011 VALUES LESS THAN(736978) ENGINE = InnoDB,
PARTITION p20171012 VALUES LESS THAN(736979) ENGINE = InnoDB,
PARTITION p20171013 VALUES LESS THAN(736980) ENGINE = InnoDB,
PARTITION p20171014 VALUES LESS THAN(736981) ENGINE = InnoDB,
PARTITION p20171015 VALUES LESS THAN(736982) ENGINE = InnoDB,
PARTITION p20171016 VALUES LESS THAN(736983) ENGINE = InnoDB,
PARTITION p20171017 VALUES LESS THAN(736984) ENGINE = InnoDB;

mysql>INSERT INTO event_history VALUES 
(1,'test','2017-10-07','2017-10-08','click','test_message') ,
(2,'test','2017-10-08','2017-10-08','click','test_message') ,
(3,'test','2017-10-09','2017-10-09','click','test_message') ,
(4,'test','2017-10-10','2017-10-10','click','test_message') ,
(5,'test','2017-10-11','2017-10-11','click','test_message') ,
(6,'test','2017-10-12','2017-10-12','click','test_message') ,
(7,'test','2017-10-13','2017-10-13','click','test_message') ,
(8,'test','2017-10-14','2017-10-14','click','test_message') ;

复制全部的表

1.在目标库上,创建与源库上定义相同的表:

mysql>USE test;

mysql>CREATE TABLE IF NOT EXISTS `event_history`(
`event_id` int(11) NOT NULL,
`event_name` varchar(10) DEFAULT NULL,
`created_at` datetime NOT NULL,
`last_updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
`event_type` varchar(10) NOT NULL,
`msg` tinytext NOT NULL,
PRIMARY KEY(`eventid`,`created_at`)
) ENGINE=InnoDBD EFAULT CHARSET=utf8mb4
PARTITION BY RANGE (to days(`created at`))
(PARTITION 2017_oct_week VALUES LESS THAN(736974) ENGINE = InnoDB,
PARTITION p20171008 VALUES LESS THAN(736975) ENGINE = InnoDB,
PARTITION p20171009 VALUES LESS THAN(736976) ENGINE = InnoDB,
PARTITION p20171010 VALUES LESS THAN(736977) ENGINE = InnoDB,
PARTITION p20171011 VALUES LESS THAN(736978) ENGINE = InnoDB,
PARTITION p20171012 VALUES LESS THAN(736979) ENGINE = InnoDB,
PARTITION p20171013 VALUES LESS THAN(736980) ENGINE = InnoDB,
PARTITION p20171014 VALUES LESS THAN(736981) ENGINE = InnoDB,
PARTITION p20171015 VALUES LESS THAN(736982) ENGINE = InnoDB,
PARTITION p20171016 VALUES LESS THAN(736983) ENGINE = InnoDB,
PARTITION p20171017 VALUES LESS THAN(736984) ENGINE = InnoDB;

2.在目标库上, Discard表空间:

mysql>ALTER TABLE event_history DISCARD TABLESPACE;
Query OK,0 rows affected(0.05sec)

3.在源库上,执行Flush TABLES FOR EXPORT

mysql>FLUSH TABLES event_history FOR EXPORT;
Query OK,0 rows affected (0.00sec)

4.在源库上,从数据目录中将所有与表相关的文件(.ibd、.cfg) 复制到目标库的数据目录:

shell>sudo scp -i /home/mysql/.ssh/id_rssa /var/lib/mysql/test/event_history#P#* mysql@xx.xxx.xxx.xxx:/var/lib/mysql/test/

5.在源库上,解锁表格,以便进行写操作:

mysql>UNLOCK TABLES;
QueryOK,0 rowS affected(0.00sec)

6.在目标库上, 确保这些文件的所有权被设置为mysql:

shell>sudo ls -lhtr /var/lib/mysql/test

7.在目标库上,导入表空间。只要表的定义相同,就可以忽略这些警告。
如果已经复制了.cfg文件, 则不会出现警告:

mysql>ALTER TABLE event_history IMPORT TABLESPACE;
Query OK,0 rows affected,12 warnings (0.31 sec)

8.在目标库上,验证数据:

mysql>SELECT count(*) FROM event_history;

如果是在生产环境,可以改进的地方
(1)如果你是在一个生产系统上执行这些操作,为了减少停机时间,可以在本地复制文件,这会非常快。立即执行UNLOCK TABLES, 然后将文件复制到目标库。

(2)如果你无法忍受停机时间, 可以使用Percona XtraBackup, 备份单个表, 并应用UNDO日志(该日志生成.ibd文件)。你可以将它们复制到目标库并导入进来。

复制表的各个分区

你在源库上添加了events_history表的一个新分区, 并且希望仅将这个新分区复制到目标库。为了便于理解, 我们先在events_history表上创建新的分区并插入几行数据:

mysql>ALTER TABLE event_history ADD PARTITION
(PARTITION p20171018 VALUES LESS THAN(736985) ENGINE = InnoDB,
PARTITION p20171019 VALUES LESS THAN(736986) ENGINE = InnoDB);
 
mysql>INSERT INTO event_history VALUES
(9,'test',2017-10-17','2017-10-17','click','test_message'),(10,'test','2017-10-18','2017-10-18','click','testmessage');

mysql>SELECT * FROM event_history PARTITION(p20171018,p20171019);

假设你希望将新建的分区复制到目标库。
1.在目标库上,创建分区:

mysql>ALTER TABLE event_history ADD PARTITION
(PARTITION p20171018 VALUES LESS THAN(736985) ENGINE = InnoDB,
PARTITION p20171019 VALUES LESS THAN(736986) ENGINE = InnoDB);

2.在目标库上, 仅Discard你想要导入的分区:

mysql>ALTER TABLE event_history DISCARD PARTITION p20171018,p20171019 TABLESPACE;

3.在源库上,执行FLUSH TABLE FOR EXPORT:

mysql>FLUSH TABLES event_history FOR EXPORT;

4.在源库上, 将分区的.ibd文件复制到目标库:

shell>sudo scp -i /home/mysql/.ssh/id_rsa \
/var/lib/mysql/test/event history#P# p20171018.ibd \
/var/lib/mysql/test/event history#P# p20171019.ibd \
mysql@192.168.0.1:/var/lib/mysql/test/

5.在目标库上, 确保所需分区的.ibd文件已被复制过来了,并将其所有者设置为mysql:

6.在目标库上,执行IMPORT PARTITION TABLESPACE:

mysql>ALTER TABLE event_history IMPORT PARTITION p20171018,p20171019 TABLESPACE;

Query OK,0 rows affected,2 warnings(0.10 sec)

只要表的定义相同, 就可以忽略这些警告。如果你已经复制了.cfg文件, 就不会有警告:

mysql>SHOW WARNINGS;

ibd 迁移数据-分区表_mysql

7.在目标库上,验证数据:

mysql>SELECT * FROM event_history PARTITION(p20171018,p20171019);

可参考文档https://dev.mysql.com/doc/refman/8.0/en/tablespace-copying.html以了解更多关于此过程的局限性。