5

我有一个数据库,它将遇到 Basecamp 在 11 月著名的整数耗尽问题。我有几个月的时间来弄清楚该怎么做。

迁移此列类型是否有无需停机的主动解决方案?如果是这样,那是什么?如果不是,是否只是消耗停机时间并尽可能迁移色谱柱?

这篇文章是否足够,假设我现在有几天/几周的时间来执行迁移,然后在我用完 id 时被迫这样做?

4

3 回答 3

8

使用逻辑复制

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

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

复制所有数据后,将应用程序切换为使用备用。

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

为此,您需要 PostgreSQL v10 或更高版本,以及您的数据库

  • 不应修改架构,因为不会复制 DDL。
  • 不应使用序列(SERIALIDENTITY),因为不会复制最后使用的值
于 2019-02-20T22:13:42.057 回答
3

对于所有事务都很短的 pre-v10 数据库的另一种解决方案:

  • 向表中添加一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。这已经足够好了,您以后可以在不中断的情况下对其进行验证。

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

于 2019-02-20T23:22:28.717 回答
2

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

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

于 2019-02-20T22:30:55.330 回答