在停机时间很少或没有停机的情况下修改超大型mysql表的列


18

我定期需要对mysql 5.1中的表进行更改,主要是添加列。使用alter table命令非常简单。但是我的表现在有多达4000万行,并且它们正在快速增长……所以那些alter table命令要花费几个小时。我猜,几个月后,他们将需要几天的时间。

由于我使用的是Amazon RDS,因此无法使用从属服务器,然后再升级为主服务器。所以我的问题是,是否有一种方法可以使停机时间最少?如果用户仍然可以使用数据库,那么我不介意花费数小时甚至数天的操作...当然,他们至少可以在添加列时读取吗?如果我的应用尝试写怎么办?插入还是更新?如果它立即失败,那实际上还不是很坏,如果它只是挂起并导致数据库服务器出现问题,那将是一个大问题。

这必须是一个相当普遍的扩展问题,每个人都需要添加列。.对生产数据库通常做什么?从站->主迁移?

更新 -我忘了说我正在使用innodb存储引擎


1
如果有人还在寻找答案..blog.staginginstance.com/… ^^
匿名编码员

Answers:


10

我定期需要对mysql 5.1中的表进行更改,主要是添加列。

别。不完全是。只是不要。这应该是一个非常难得的机会时,这是以往任何时候都需要。

假设您的数据确实从一开始就被规范化了,那么解决该问题的正确方法是向基表中添加一个具有1:1关系的新表(在新表上不是必须的)。

通常必须定期添加列通常是未规范化数据库的指示-如果您的架构未规范化,那么这就是您需要解决的问题。

最后,如果您的架构确实被规范化并且您确实必须继续添加列,则:

  1. 确保数据库上有一个时间戳列,或者它正在生成复制日志
  2. 创建表(A)的副本(B)
  3. 将新列添加到B(这仍然会被myisam阻止)
  4. 禁用交易
  5. 重命名原始表(A)为其他名称(备份)
  6. 使用原始表(A)的名称重命名新表(B)
  7. 从复制日志或备份表的操作开始重放事务
  8. 启用交易。

2
感谢您的逐步方法。修改表格真的不常见吗?我知道我可以改为使用新列添加另一个表(在需要添加列的情况下),并使它以1:1关系引用原始大表。但是,当15个非常大的1:1表都应该放在1个表中时,这似乎是不对的。当然,查询性能也会受到影响,更不用说索引问题了。我不是专家,但是我的数据库已被很好地规范化,因此我需要定期进行修改似乎很自然
。.– apptree

2
“修改表真的不常见吗?” -是的
symcbean

1
不,但是有人可以说,如果这是正常发生的-不是作为主要软件升级的一部分-那么就需要解雇某人,因为他们没有意识到所有表都应该放在第一位。这里的问题/技巧是“定期”,而不是“每隔几个月一次”。
TomTom 2014年

22
作为一名开发人员,尤其是那些在初创公司和年轻公司工作的开发人员,我对symcbean和@TomTom表示同意。事情改变了,产品改变了,业务目标改变了,数据库结构也需要随之改变。提供良好的DBA服务意味着对那些更改说“是”,然后弄清楚如何有效地实施它们。高度规范化的数据库是一个很久以前就死掉的概念。它们会导致性能下降和缓慢的开发周期。
pents90

4
罕见地更改表???也许在大型公司中,但是在经常发生的敏捷团队中,需求会发生变化……
tibo 2015年

12

我最近不得不这样做。亚马逊建议使用Percona工具包。我下载了它,并能够运行以下内容:

./pt-online-schema-change h=databasenameHostName,D=databasename,t=tablename --recursion-method=none --execute --user username --password password --alter "MODIFY someColumn newDataType"

而且效果很好。它告诉您过程中还剩下多少时间。

实际上,它使用新列创建了一个新表,然后将现有数据复制过来。此外,它创建触发器,以便新数据也被推到新表上。然后,它会自动重命名表,删除旧表,然后使用新列启动并运行,而在等待更新时不会停机。


Percona团队简要介绍了通过pt-online-schema-change工具要求的RDS参数组(因为SET GLOBAL log_bin_trust_function_creators = 1在RDS上不起作用)来启用log_bin_trust_function_creators功能。更多详细信息:percona.com/blog/2016/07/01/pt-online-schema-change-amazon-rds
user1652110 16-10-25

它为我工作
Adiii

4

symcbean提供了一些可靠的建议

要回答您的问题,减轻影响的最简单,最佳方法是复制多个数据库。具有适当故障转移过程的双主服务器停止在活动数据库上的复制,这允许更改非活动数据库而不影响活动数据库。

您可以在单个实时数据库上执行此操作,并通过使用与本答案中详述的过程类似的过程来最大程度地减少影响。诚然,这与symcbean所描述的相似,但包含技术细节。您也可以使用auto_increment字段,而不仅仅是时间戳。

最终,如果您的数据集增长得如此之大,则还需要考虑OLTPOLAP数据库之间的归档。如果设计适当,则交易数据集不必太大。


2

从手册中:http : //dev.mysql.com/doc/refman/5.1/en/alter-table.html

在大多数情况下,ALTER TABLE会创建原始表的临时副本。MySQL将更改合并到副本中,然后删除原始表并重命名新表。执行ALTER TABLE时,其他会话可以读取原始表。对该表的更新和写入将被暂停,直到准备好新表为止,然后将其自动重定向到新表,而不会进行任何失败的更新。

因此,阅读会很好。写入将停止,但随后将执行。如果要防止这种情况,则必须修改软件。


因此,我完成了此操作,并禁用了我网站中写入到当前正在修改的表中的部分。到目前为止,我收到了几个“超出了锁定等待超时;尝试重新启动事务”的异常,这还不错。但是,他们只能进行纯读操作...
10年

0

我处于类似的情况,我必须更改我的交易表中的将近65GB。我听到2个解决方案

  1. 使用直接ALTER并使其运行(X小时或天数)
  2. 确保数据库上有一个时间戳列,或者它正在生成复制日志
    • 创建表(A)的副本(B)
    • 将新列添加到B(这仍然会被myisam阻止)
    • 禁用交易
    • 重命名原始表(A)为其他名称(备份)
    • 使用原始表(A)的名称重命名新表(B)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.