将大型InnoDB表复制为文件?

问题描述:

我们有一个巨大的InnoDB表(153G),我们需要移动到另一台服务器。我们使用innodb_file_per_table。有没有办法以某种方式复制IBD文件?目标数据库如何识别文件并了解其元数据? 如果需要,我们可以停止复制数据库。将大型InnoDB表复制为文件?

编辑: 一个大表是这样的:

CREATE TABLE `140M_table` (
    `field1` bigint(20) NOT NULL AUTO_INCREMENT, 
    `field2` datetime DEFAULT NULL, 
    `field3` varchar(255) DEFAULT NULL, 
    `field4` int(11) DEFAULT NULL, 
    `field5` varchar(255) DEFAULT NULL, 
    `field6` varchar(255) DEFAULT NULL, 
    `field7` int(11) DEFAULT NULL, 
    `field8` bigint(20) DEFAULT NULL, 
    `field9` varchar(20) DEFAULT NULL, 
    PRIMARY KEY (`field1`), 
    KEY `captureDateIdx` (`field2`,`feild6`), 
    KEY `personaSubIdx` (`field3`,`field6`,`field5`), 
    KEY `FKE6B5072DF27AF1FE` (`field8`), 
    KEY `FKE6B5072D54F7256A` (`field7`), 
    KEY `temp_key_idx` (`field9`), 
    CONSTRAINT `FKE6B5072D54F7256A` FOREIGN KEY (`field7`) REFERENCES `small_table`  (`field7`), 
    CONSTRAINT `FKE6B5072DF27AF1FE` FOREIGN KEY (`field8`) REFERENCES `2M_table` (`field9`) 
) ENGINE=InnoDB AUTO_INCREMENT=136181731 DEFAULT CHARSET=latin1 
+3

为什么不暂时设置异步复制?这样,您甚至可以在复制时获得新的和修改的数据... – 2011-05-31 15:43:50

+0

这是为迁移而完成的。我们需要尽量减少停机时间窗口。因此,我们希望在单独的机器上导入大型表格,然后将它们合并到一个数据库中。 – Philopator 2011-05-31 18:02:45

+0

这是我问题的要点......如果你异步复制,你的宕机时间为零。 – 2011-05-31 21:59:10

你不能只是复制InnoDB表。即使使用innodb_file_per_table,所有InnoDB文件也共享一个*“缓存”文件(ibdata#,ib_logfile#),这些文件存储在mysql数据目录的根目录下。

您需要将所有InnoDB表和共享缓存文件复制到新服务器,或转储表。由于您在3次“移动”数据(转储,复制,恢复)之后,转储表格可能会花费相当长的时间。确保两台服务器上的my.cnf中的InnoDB设置相同,否则在尝试在新服务器上启动mysql时会出错。

+0

这就是我的想法,但问题是目标环境的ibdata,ib_logfile发生了什么。这个想法是加载comp1上的一个大表,comp2上的另一个大表,然后将第二个表从comp2移动到comp1。如果我们复制ibdata,ib_logfile,它会终止comp1的内容。即使我们将它移动到comp3,我们也不能同时移动comp1和comp2的ibdata和ib_logfile。 – Philopator 2011-06-03 19:04:13

+0

听起来像你正试图合并两个系统。你不能用InnoDB表来做到这一点。倾销是唯一/最快捷的方式。你可以通过nfs在comp2上安装comp1并直接转储到安装盘来加快速度。然后你避免转储+复制。 – 2011-06-04 00:06:35

+0

@ brent-baisley,如果我到mysqldump,我需要加载它,这与运行LOAD DATA INFILE一样慢。 – Philopator 2011-06-06 15:20:10

随着分区的帮助下,问题会得到解决的ubder:

CREATE TABLE test_part_innodb (c1 int default NULL, c2 varchar(30) default NULL, c3 date default NULL) engine=InnoDB 
-> PARTITION BY RANGE (year(c3)) (PARTITION p0 VALUES LESS THAN (2000), 
-> PARTITION p1 VALUES LESS THAN (2001) , PARTITION p2 VALUES LESS THAN (2002) , 
-> PARTITION p3 VALUES LESS THAN (2003) , PARTITION p4 VALUES LESS THAN (2004) , 
-> PARTITION p5 VALUES LESS THAN (2005) , PARTITION p6 VALUES LESS THAN (2006) , 
-> PARTITION p7 VALUES LESS THAN (2007) , PARTITION p8 VALUES LESS THAN (2008) , 
-> PARTITION p9 VALUES LESS THAN (2009) , PARTITION p10 VALUES LESS THAN (2010), 
-> PARTITION p99 VALUES LESS THAN MAXVALUE); 
Query OK, 0 rows affected (0.13 sec) 



show create table test_part_innodb\G; 
*************************** 1. row *************************** 
Table: test_part_innodb 
Create Table: CREATE TABLE `test_part_innodb` (
`c1` int(11) DEFAULT NULL, 
`c2` varchar(30) DEFAULT NULL, 
`c3` date DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
/*!50100 PARTITION BY RANGE (year(c3)) 
(PARTITION p0 VALUES LESS THAN (2000) ENGINE = InnoDB, 
PARTITION p1 VALUES LESS THAN (2001) ENGINE = InnoDB, 
PARTITION p2 VALUES LESS THAN (2002) ENGINE = InnoDB, 
PARTITION p3 VALUES LESS THAN (2003) ENGINE = InnoDB, 
PARTITION p4 VALUES LESS THAN (2004) ENGINE = InnoDB, 
PARTITION p5 VALUES LESS THAN (2005) ENGINE = InnoDB, 
PARTITION p6 VALUES LESS THAN (2006) ENGINE = InnoDB, 
PARTITION p7 VALUES LESS THAN (2007) ENGINE = InnoDB, 
PARTITION p8 VALUES LESS THAN (2008) ENGINE = InnoDB, 
PARTITION p9 VALUES LESS THAN (2009) ENGINE = InnoDB, 
PARTITION p10 VALUES LESS THAN (2010) ENGINE = InnoDB, 
PARTITION p99 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 
1 row in set (0.00 sec) 


delimiter // 
CREATE PROCEDURE load_test_part_innodb() 
begin 
do 
declare v int default 0; 
while v do 
insert into test_part_innodb 
values (v,'testing partitions',adddate('2000-01-01',(rand(v)*36520) mod 3652)); 
set v = v + 1; 
end while; 
end 
// 
Query OK, 0 rows affected (0.00 sec) 

delimiter ; 
call load_test_part_innodb(); 
Query OK, 1 row affected (1 hour 11 min 25.19 sec) 

select count(*) from test_part_innodb where c3 > date '2000-01-01' and c3 < date '2000-12-31'; 
+----------+ 
| count(*) | 
+----------+ 
| 99681 | 
+----------+ 
1 row in set (0.22 sec) 


show create view part_backup\G; 
    *************************** 1. row *************************** 
    View: part_backup 
    Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `part_backup` AS select 

    concat('mysqldump',' -u root',' -p ',' --no-create-info',' --where="',(case `p2`.`PARTITION_METHOD` when 'hash' then 
    concat(`p2`.`PARTITION_EXPRESSION`,' % ',(select count(0) from `information_schema`.`partitions` `p3` where ((`p3`.`TABLE_SCHEMA` = 
    `p2`.`TABLE_SCHEMA`) and (`p3`.`TABLE_NAME` = `p2`.`TABLE_NAME`))),' = ',(`p2`.`PARTITION_ORDINAL_POSITION` - 1)) when 'list' then 
    concat(`p2`.`PARTITION_EXPRESSION`,' in (',`p2`.`PARTITION_DESCRIPTION`,')') when 'range' then 
    concat(if((`p2`.`PARTITION_ORDINAL_POSITION` = 1),'',concat(`p2`.`PARTITION_EXPRESSION`,' >= 
    ',replace(`p1`.`PARTITION_DESCRIPTION`,'MAXVALUE',~(0)),' and ')),concat(`p2`.`PARTITION_EXPRESSION`,' 
    ',`p2`.`TABLE_SCHEMA`,'.',`p2`.`TABLE_NAME`) AS `Name_exp_1` from (`information_schema`.`partitions` `p2` left join 
    `information_schema`.`partitions` `p1` on(((`p1`.`TABLE_SCHEMA` = `p2`.`TABLE_SCHEMA`) and (`p1`.`TABLE_NAME` = `p2`.`TABLE_NAME`) and 

    ((`p1`.`PARTITION_ORDINAL_POSITION` + 1) = `p2`.`PARTITION_ORDINAL_POSITION`)))) where ((`p2`.`TABLE_SCHEMA` = database()) and 
    (`p2`.`PARTITION_METHOD` in ('hash','list','range'))) 
    character_set_client: utf8 
    collation_connection: utf8_general_ci 
    1 row in set (0.01 sec) 

desc part_backup; 
+------------+------------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+------------+------------+------+-----+---------+-------+ 
| Name_exp_1 | mediumtext | YES | | NULL | | 
+------------+------------+------+-----+---------+-------+ 
1 row in set (0.02 sec) 

select * from part_backup; 
+0

谢谢。这看起来像一个有趣的解决方案,但同时它有点复杂。另外,它似乎依靠mysqldump。使用mysqldump然后加载转储,就像执行LOAD DATA INFILE一样慢。 – Philopator 2011-06-06 15:22:25

+0

@Philopator在数据量非常大的情况下使用此过程,因为在目前的情况下,数据大约为153GB,而通过mysqldump做的事情必须连续写入数据,如果需要1分钟写入1GB数据,则需要153 2.5小时的另一件事数据库大小为153GB,但转储大小为最大160GB,因为增加了“和,另一个如何携带153GB数据库,唯一的方法是通过硬盘完成,但在这种方法中,可以制作碎片并且每个片段都可以被压缩,这将减小大小约50%,并轻松传输数据 – Vineet1982 2011-06-06 21:05:09

+0

我认为问题会在加载mysqldump。这将需要永远。但感谢您的想法。 – Philopator 2011-06-07 14:20:31