将 MySQL 表列类型从 INT 更改为 BIGINT

use*_*891 9 mysql ruby-on-rails alter

我有一个包含不到 5000 万行的表。它达到了 INT 的限制 (2147483647)。目前该表尚未被写入。

我计划将 ID 列从 INT 更改为 BIGINT。我正在使用 Rails 迁移通过以下迁移来执行此操作:

  def up
    execute('ALTER TABLE table_name MODIFY COLUMN id BIGINT(8) NOT NULL AUTO_INCREMENT')
  end
Run Code Online (Sandbox Code Playgroud)

我已经在 2000 行的数据集上进行了本地测试,效果很好。在 5000 万条上运行ALTER TABLE命令应该没问题,因为目前该表没有被使用?

我想在运行迁移之前进行检查。任何意见将不胜感激,谢谢!

Zia*_*hal 7

我们有完全相同的场景,但是使用 postgresql,我知道 50M 如何填充 int 的整个范围,它在 ids 中的间隙,随着时间的推移删除行或涉及不完整事务的其他因素产生的间隙等。

我将解释我们最终做了什么,但首先,严肃地说,在 2k 行上测试 50M 行的数据迁移并不是一个好的测试。

这个问题可以有多种解决方案,具体取决于您使用哪个数据库提供商等因素?我们使用的是 mazon RDS,它对运行时以及他们所说的 IOPS(输入/输出操作)有限制,如果我们在具有此类限制的数据库上运行如此密集的查询,它将在中途耗尽其 IOPS 配额,并且当 IOPS 配额达到时耗尽了,数据库最终变得太慢而且毫无用处。我们必须取消查询,让 IOPS 赶上,这大约需要 30 分钟到 1 小时。

如果您没有这样的限制并且在本地有数据库或类似的东西,那么还有另一个因素,那就是您是否可以承受停机时间?**

如果您可以承受停机时间并且数据库上没有 IOPS 类型限制,您可以直接运行此查询,这将花费大量时间(可能半小时左右,取决于很多因素),同时

  • 当行被更改时,表将被锁定,因此请确保该表不仅没有任何写入,而且在此过程中也没有读取,以确保您的过程顺利结束,没有任何死锁类型的情况。

我们为避免停机和 Amazon RDS IOPS 限制所做的工作:

就我而言,当我们意识到表中还剩下大约 40M 个 id 时,我们希望避免停机。因此我们采取了多步骤的方法:

  1. 创建一个新的 big_int 列,将其命名为 new_id 或其他名称(使其从一开始就具有唯一索引),这将可以为空,默认为 null。
  2. 编写每晚运行几次的后台作业,并new_idid列中回填列。我们每晚回填大约 4-5M 行,周末回填更多(因为我们的应用程序在周末没有流量)。
  3. 当您陷入回填时,现在我们将不得不停止对此表的任何访问(我们刚刚在晚上关闭了我们的应用程序几分钟),并从 max(new_id) 值开始创建一个新序列,或者使用现有的序列序列并将其绑定到该序列的默认值为 tonextval的 new_id 列。
  4. 现在将主键从 id 切换到 new_id,在此之前使 new_id 不为空。
  5. 删除 id 列。
  6. 将 new_id 重命名为 id。
  7. 并恢复您的数据库操作。

上面是我们所做的最小的记录,你可以在谷歌上搜索一些关于它的好文章,其中之一就是这个。这种方法并不新鲜,而且很常见,所以我相信你也会找到 mysql 特定的方法,或者你可以在上面的文章中调整一些东西,你应该可以开始了。