我有一张包含约 3 亿行 MyISAM 格式的表,我想将其转换为 Innodb
我最初的目标是通过更改表架构以使用更简单的索引来减少使用量。我转储了所有表,删除了它,用更少的索引重新创建了它,现在正在重新导入。但是,我忘了指定它应该是 innodb 而不是 myisam。
我可以只执行标准的 ALTER TABLE ... ENGINE=INNODB 吗?对于如此庞大的表,有什么需要注意的吗?
数据导入操作大约需要 12 个小时——我不愿意再做一次。因此我只想转换它。
答案1
以下摘录自本书“高性能 MySQL,第二版“。
这是一本很棒的书,我会向任何人推荐它。
简短的回答是:
考虑到您的桌子大小和条件,无论您选择哪种方法,我认为您都可能需要等待很长时间。
表转换
有多种方法可以将表从一种存储引擎转换为另一种存储引擎,每种方法都有优点和缺点。
修改表
mysql> ALTER TABLE mytable ENGINE = Falcon;
此语法适用于所有存储引擎,但有一个问题:它可能需要很长时间。MySQL 将逐行复制旧表到新表。在此期间,您可能会使用服务器的所有磁盘 I/O 容量,并且原始表将在转换运行时处于读锁定状态。
转储和导入
为了更好地控制转换过程,您可以选择先使用 mysqldump 实用程序将表转储到文本文件。转储表后,您可以简单地编辑转储文件以调整其中包含的 CREATE TABLE 语句。一定要更改表名及其类型,因为您不能在同一个数据库中拥有两个同名的表,即使它们是不同类型的 - 并且 mysqldump 默认在 CREATE TABLE 之前写入 DROP TABLE 命令,因此如果您不小心,可能会丢失数据!
创建并选择
第三种转换技术是第一种机制的速度和第二种机制的安全性之间的折衷。不是转储整个表或一次性转换所有内容,而是创建新表并使用 MySQL 的 INSERT ... SELECT 语法来填充它,如下所示:
mysql> CREATE TABLE innodb_table LIKE myisam_table;
mysql> ALTER TABLE innodb_table ENGINE=InnoDB;
mysql> INSERT INTO innodb_table SELECT * FROM myisam_table;
如果您没有太多数据,这种方法效果很好,但如果数据量很大,则逐步填充表通常更有效,在每个块之间提交事务,这样撤消日志就不会变得很大。假设 id 是主键,重复运行此查询(每次使用较大的 x 和 y 值),直到将所有数据复制到新表:
mysql> START TRANSACTION;
mysql> INSERT INTO innodb_table SELECT * FROM myisam_table
-> WHERE id BETWEEN x AND y;
mysql> COMMIT;
执行此操作后,您将剩下原始表(您可以在完成后将其删除)和新表(现在已完全填充)。如果需要,请小心锁定原始表,以防止获得不一致的数据副本!
答案2
ALTER TABLE 语句本质上做同样的事情:服务器创建一个临时表,复制所有行,然后执行 RENAME。InnoDB 和 MyISAM 之间的磁盘格式非常不同,所以我不指望你能找到任何捷径。
另一点(您可能已经注意到了,但这有助于阅读本文的其他人):InnoDB 的磁盘格式高度依赖于主键,因为它基于主键对记录进行聚类。因此,在使用大型 InnoDB 表时,在选择主键之前请三思,因为更改主键会重建整个表,就像手头的问题一样。
无论如何,我建议先在中等大小的桌子上做一些测试并计时。