我定期需要对 mysql 5.1 中的表进行更改,主要是添加列。使用 alter table 命令非常简单。但是我的表现在有多达 4000 万行,而且它们增长得很快……所以这些 alter table 命令需要几个小时。我猜几个月后它们会花几天时间。
由于我使用的是 amazon RDS,因此我无法使用从服务器,然后再将其提升为主服务器。所以我的问题是,是否有办法以最少的停机时间做到这一点?当然,如果用户仍然可以使用数据库,我不介意操作花费数小时甚至数天的时间……他们至少可以在添加列时读取吗?如果我的应用程序尝试写入会发生什么?插入还是更新?如果它立即失败,那实际上并不是那么糟糕,如果它只是挂起并导致数据库服务器出现问题,那就是一个大问题了。
这肯定是一个相当常见的扩展问题,每个人都需要添加列。通常对生产数据库做什么?从数据库 -> 主数据库迁移?
更新- 我忘了说我使用的是 innodb 存储引擎
答案1
我需要定期对 mysql 5.1 中的表进行更改,主要是添加列。
不要。真的不要。不要。这种情况应该很少见曾经必要的。
假设您的数据确实是从一开始就规范化的,那么解决问题的正确方法是添加一个与基表具有 1:1 关系的新表(在新表上不是强制性的)。
必须定期添加列通常表明数据库未规范化 - 如果您的模式未规范化,那么这就是您需要修复的问题。
最后,如果您的模式确实已经规范化,并且您确实必须继续添加列,那么:
- 确保数据库中有一个时间戳列,或者它正在生成复制日志
- 创建表 (A) 的副本 (B)
- 将新列添加到 B(这仍然会阻止 myisam)
- 禁用交易
- 将原始表(A)重命名为其他名称(备份)
- 将新表 (B) 重命名为原始表 (A) 的名称
- 从复制日志或备份表中重播操作开始处的事务
- 启用交易。
答案2
我最近不得不这么做。亚马逊推荐使用 Percona Toolkit。我下载了它并能够运行如下命令:
./pt-online-schema-change h=databasenameHostName,D=databasename,t=tablename --recursion-method=none --execute --user username --password password --alter "MODIFY someColumn newDataType"
而且效果很好。它会告诉你这个过程还剩多少时间。
它实际上会创建一个包含新列的新表,然后复制现有数据。此外,它还会创建一个触发器,以便将新数据也推送到新表中。然后它会自动重命名表,删除旧表,然后您就可以使用新列开始运行,并且在等待更新时不会出现停机时间。
答案3
答案4
我遇到过类似的情况,我必须更改我的 1 个事务表,该表几乎有 65GB。我听到了 2 个解决方案
- 使用直接 ALTER 并让其运行(X 小时或天)
- 确保数据库中有一个时间戳列,或者它正在生成复制日志
- 创建表 (A) 的副本 (B)
- 将新列添加到 B(这仍然会阻止 myisam)
- 禁用交易
- 将原始表(A)重命名为其他名称(备份)
- 将新表 (B) 重命名为原始表 (A) 的名称