在没有任何停机时间的情况下将 PostgresQL 中的 `int` 迁移到 `bigint`?
Migrating `int` to `bigint` in PostgresSQL without any downtime?
我有一个数据库,它将体验 Basecamp 在 11 月著名地面对的 integer exhaustion problem。我有几个月的时间来弄清楚该怎么做。
是否有无需停机的主动解决方案来迁移此列类型?如果有,那是什么?如果不是,是否只是吃掉停机时间并尽可能迁移列的问题?
是this article sufficient,假设我有几个days/weeks来执行迁移现在,然后我运行被迫这样做] 没有 ID?
通过逻辑复制,您可以在主数据库和备用数据库中拥有不同的数据类型。
使用 pg_dump -s
复制架构,更改副本上的数据类型,然后开始逻辑复制。
复制完所有数据后,将应用程序切换为使用备用。
对于零停机时间,应用程序必须能够重新连接并重试,但在这种情况下,这始终是一项要求。
您需要 PostgreSQL v10 或更高版本,以及您的数据库
- 不应修改架构,因为 DDL 未被复制。
- 不应使用序列(
SERIAL
或 IDENTITY
),因为最后使用的值不会是 replicated
创建旧 table 的副本,但修改了 ID 字段。接下来在旧 table 上创建一个触发器,将新数据插入到两个 table 中。最后将数据从旧的 table 复制到新的(如果是顺序的,最好用 post-trigger 区分预触发数据,例如通过 id)。完成后切换 tables 并删除旧的。
这显然需要两倍的 space(和复制时间),但无需 任何 停机时间即可工作。
v10 之前的数据库的另一种解决方案所有事务都很短:
将 bigint
列添加到 table。
创建一个 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
个外键。
我有一个数据库,它将体验 Basecamp 在 11 月著名地面对的 integer exhaustion problem。我有几个月的时间来弄清楚该怎么做。
是否有无需停机的主动解决方案来迁移此列类型?如果有,那是什么?如果不是,是否只是吃掉停机时间并尽可能迁移列的问题?
是this article sufficient,假设我有几个days/weeks来执行迁移现在,然后我运行被迫这样做] 没有 ID?
通过逻辑复制,您可以在主数据库和备用数据库中拥有不同的数据类型。
使用 pg_dump -s
复制架构,更改副本上的数据类型,然后开始逻辑复制。
复制完所有数据后,将应用程序切换为使用备用。
对于零停机时间,应用程序必须能够重新连接并重试,但在这种情况下,这始终是一项要求。
您需要 PostgreSQL v10 或更高版本,以及您的数据库
- 不应修改架构,因为 DDL 未被复制。
- 不应使用序列(
SERIAL
或IDENTITY
),因为最后使用的值不会是 replicated
创建旧 table 的副本,但修改了 ID 字段。接下来在旧 table 上创建一个触发器,将新数据插入到两个 table 中。最后将数据从旧的 table 复制到新的(如果是顺序的,最好用 post-trigger 区分预触发数据,例如通过 id)。完成后切换 tables 并删除旧的。
这显然需要两倍的 space(和复制时间),但无需 任何 停机时间即可工作。
v10 之前的数据库的另一种解决方案所有事务都很短:
将
bigint
列添加到 table。创建一个
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
个外键。