43

对于 MySQL 中超过 1000 万行的大型 innodb 表,添加新列或添加新索引可能需要数小时和数天。在这两种情况下,提高大型 innodb 表性能的最佳方法是什么?更多内存,调整配置(例如增加sort_buffer_sizeinnodb_buffer_pool_size),还是某种技巧?与其直接更改表,不如创建一个新表,对其进行更改,然后将旧数据复制到新表中,就像这样对ISAM 表多项更改很有用:

CREATE TABLE tablename_tmp LIKE tablename;
ALTER TABLE tablename_tmp ADD fieldname fieldtype;
INSERT INTO tablename_tmp SELECT * FROM tablename;
ALTER TABLE tablename RENAME tablename_old;
ALTER TABLE tablename_tmp RENAME tablename;

它是否也适用于 innodb 表,或者它只是 ALTER TABLE 命令所做的吗?

4

2 回答 2

72

2016 年编辑:我们最近(2016 年 8 月)发布了gh-ost,修改了我的答案以反映它。

今天有几个工具可以让你为 MySQL 做在线修改表。这些是:

让我们考虑“正常”的 `ALTER TABLE`:

一张大桌子要花很长时间ALTERinnodb_buffer_pool_size很重要,其他变量也很重要,但在非常大的桌子上它们都可以忽略不计。只是需要时间。

MySQL 对ALTER表所做的就是创建一个具有新格式的新表,复制所有行,然后切换。在此期间,表完全锁定。

考虑你自己的建议:

它很可能会在所有选项中表现最差。这是为什么?因为您使用的是 InnoDB 表,所以INSERT INTO tablename_tmp SELECT * FROM tablename会产生事务。一笔巨额交易。它会产生比正常更多的负载ALTER TABLE

此外,您必须在那时关闭您的应用程序,以便它不会将 ( INSERT, DELETE, UPDATE) 写入您的表。如果是这样 - 您的整个交易毫无意义。

在线工具提供什么

这些工具并非都一样。但是,基础是共享的:

  • 他们用改变的模式创建了一个“影子”表
  • 他们创建并使用触发器将更改从原始表传播到幽灵表
  • 他们慢慢地将所有行从您的表复制到影子表。他们分块进行:比如说,一次 1,000 行。
  • 当您仍然能够访问和操作原始表时,它们会执行上述所有操作。
  • 满意后,他们使用RENAME.

openark -kit工具已经使用了 3.5 年。Percona 工具已有几个月的历史,但可能比前者经过更多测试。据说 Facebook 的工具适用于 Facebook,但没有为普通用户提供通用解决方案。我自己没用过。

Edit 2016: gh-ost是一个无触发的解决方案,它显着减少了主控上的主控写入负载,将迁移写入负载与正常负载解耦。它是可审计的、可控的、可测试的。我们在 GitHub 内部开发了它并作为开源发布;我们正在通过gh-ost今天进行所有生产迁移。在这里查看更多。

每个工具都有其自身的局限性,请仔细查看文档。

保守的方式

保守的方法是使用主动-被动主-主复制,ALTER在备用(被动)服务器上执行,然后切换角色并ALTER在以前的主动服务器上再次执行,现在变成被动服务器。这也是一个不错的选择,但需要额外的服务器和更深入的复制知识。

于 2012-07-12T11:03:27.383 回答
0

重命名会破坏引用的表。

如果你有说table_2哪个是child to tablename,onALTER TABLE tablename RENAME tablename_old; table_2会开始指向tablename_old

现在不改变 table_2 你不能把它指向tablename. 您必须继续在每个子表和引用表中进行更改。

于 2015-10-08T22:23:10.463 回答