如何将列添加到 MySQL 中的大表

ine*_*rsa 16 mysql innodb

我是一名 PHP 开发人员,所以不要太严格。我有一个大表 ~5.5gb 转储。我们的 PM 决定在其中创建新列以执行新功能。表是 InnoDB 所以我试过:

  1. 使用表锁定更改屏幕中的表。花了大约 30 小时,一无所获。所以我只是阻止了它。首先我犯了一个错误,因为我没有结束所有交易,但第二次没有多锁。状态是copy to tmp table

  2. 由于我还需要为此表应用分区,因此我们决定使用相同的名称和新结构进行转储、重命名和制作表。但是转储正在制作严格的副本(至少我没有发现其他东西)。所以我添加了转储一个新列sed并查询它。但是一些奇怪的错误开始了。我相信这是由字符集引起的。utf-8 中的表和文件在sed. 所以我在 30% 的数据上遇到了错误(未知命令 '\'')。所以这也是一种不好的方式。

还有哪些其他选项可以实现这一点并提高性能(我可以使用 php 脚本来完成,但需要很长时间)。INSERT SELECT在这种情况下会有什么表现。

感谢您的任何提前。

小智 16

使用MySQL 工作台。您可以右键单击一个表并选择“发送到 SQL 编辑器”-->“创建语句”。这样就不会忘记添加表“属性”(包括CHARSETCOLLATE)。
对于如此大量的数据,我建议清理您使用的表或数据结构(一个好的 DBA 会派上用场)。如果不可能:

  • 重命名表 ( ALTER) 并使用CREATE您从 Workbench 获得的脚本创建一个新表。您还可以使用您需要的新字段扩展该查询
  • 将旧表中的数据批量加载到新表中:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;
    
    Run Code Online (Sandbox Code Playgroud)
    这样您就可以避免索引/等以逐条记录运行。表的“更新”仍然会很慢(因为数据量很大),但这是我能想到的最快的方法。

    编辑:阅读文章,以获取有关在上面的示例查询中使用的命令的详细信息;)


小智 12

alter table add column, algorithm=inplace, lock=none 将更改 MySQL 5.6 表而不复制表且不会影响锁定。

昨天刚刚测试过,将 70K 行批量插入到 280K 第 7 行的分区表中,每个分区插入 10K 行,中间有 5 秒的睡眠时间以允许其他吞吐量。

开始批量插入,然后在单独的会话中alter在 MySQL Workbench 中启动上面的在线语句,alter插入之前完成,添加了两个新列,并且没有行导致更改意味着 MySQL 没有复制任何行。

  • 为什么这个答案没有获得更多选票?,它不起作用吗? (4认同)

Der*_*ney 6

您的 sed 想法是一种不错的方法,但是如果没有错误或您运行的命令,我们将无法帮助您。

但是,对大型表进行在线更改的一种众所周知的方法是pt-online-schema-change。从文档中复制了对该工具功能的简单忽略:

pt-online-schema-change 通过创建表的空副本进行更改,根据需要修改它,然后将原始表中的行复制到新表中。复制完成后,它会移走原始表格并用新表格替换它。默认情况下,它还删除原始表。

此方法可能也需要一段时间才能完成,但在此过程中,原始表将完全可用。