在PostgresSQL中将int迁移到bigint而不造成任何停机?

时间:2019-02-20 21:44:15

标签: postgresql database-migration downtime

我有一个数据库,该数据库将体验11月著名的Basecamp面对的integer exhaustion problem。我有几个月要弄清楚该怎么办。

是否存在无需停机的主动解决方案来迁移此列类型?如果是这样,那是什么?如果不是,那么我可以只吃顿停机时间并迁移色谱柱吗?

this article sufficient是不是假设我有几天/几周的时间要执行迁移,现在又要立即,当我用完ID之前,我被迫执行迁移?

3 个答案:

答案 0 :(得分:3)

使用logical replication

使用逻辑复制,您可以在主数据库和备用数据库中拥有不同的数据类型。

使用pg_dump -s复制架构,更改副本上的数据类型,然后开始逻辑复制。

所有数据复制完毕后,切换应用程序以使用备用数据库。

要实现零停机时间,应用程序必须能够重新连接并重试,但这在这种情况下始终是必需的。

为此,您需要PostgreSQL v10或更高版本,并且您的数据库不应修改架构,因为不会复制DDL。

答案 1 :(得分:2)

创建旧表的副本,但ID字段已修改。接下来,在旧表上创建一个触发器,该触发器将新数据插入两个表中。最后,将数据从旧表复制到新表中(如果是连续的,最好通过id将前触发数据和后触发数据区分开来)。完成后,切换表并删除旧表。

这显然需要两倍的空间(和复制时间),但可以在没有任何停机时间的情况下工作。

答案 2 :(得分:1)

针对所有交易都很短的v10之前版本的数据库的另一种解决方案

  • 向表中添加var output = Array(Math.max(...input.map(arr => arr.length))).fill().map((_,i) => i) .map(i => input.map(arr => arr[i] )) .flat().filter(el => el !== undefined) 列。

  • 创建一个bigint触发器,该触发器将在添加或更新行时设置新列。

  • 运行一系列更新,将新列从旧列设置为BEFORE。使这些批次短一些,这样您就不会锁定太长时间,也不会死锁太多。确保这些事务以IS NULL运行,因此它们不会触发触发器。

  • 所有行都更新后,在新列上创建唯一索引session_replication_role = replica

  • 为您刚创建的索引添加唯一约束CONCURRENTLY。那会很快。

  • 执行切换:

    USING

    那会很快。

您的新列未设置BEGIN; ALTER TABLE ... DROP oldcol; ALTER TABLE ... ALTER newcol RENAME TO oldcol; COMMIT; 。没有长期的侵入性锁,就无法做到这一点。但是您可以添加检查约束NOT NULL并创建IS NOT NULL。这样就足够了,您以后可以在不中断的情况下对其进行验证。

如果有外键约束,事情会变得更加复杂。您必须删除它们并为新列创建NOT VALID外键。