将 table 中的整数更改为 bigint 密钥,无需长排他锁

Change integer to bigint key in a table without long exclusive lock

在 PostgreSQL 9.1 中是否可以从具有相同类型 bigint 列的 table 继承具有类型 int 列的 table?

如果第一个 table 不是一个选项,则将列类型更改为 bigint

我有一个 table,其中包含数千万个 ID 为 int 的条目。现在这个ID慢慢接近2^32,我在想用bigint ID创建一个门面table,让原来的门面继承这个门面是否合理。这有意义吗?

不,当您从 table 继承时,无法更改父 table 的列的类型。

列类型必须匹配,因为当您查询父 table(在 FROM 子句中没有 ONLY)时,PostgreSQL 隐式扫描子 tables也附上他们的结果。如果类型不同,它就无法做到这一点,就像您不能 UNION table 不同类型一样。

根据评论更新:

使用视图和 DO INSTEAD 触发器

我建议使用一个视图,它是两个 table 的联合视图,旧 table 的内容向上转换为 bigint。定义一个 INSTEAD OF 触发器,将 INSERT 重定向到新的 table.

如果您执行 UPDATEs 和 DELETEs,您可能应该在每个 table 上定义一个 CHECK 约束,将 ID 的范围限制为不重叠范围,然后根据 ID 决定将 DELETEUPDATE 路由到哪个 table。

对于 UPDATE,您甚至可以将其转换为 DELETE ... RETURNINGINSERT(可能在 wCTE 中)以将行从旧的 table 移动到新的作为更新的一部分。

招致性能损失,但你将避免需要完全 table 重写。

逐步就地更改密钥类型

你说更改密钥类型不是一个选项,但你的意思似乎是 "changing the key type in a manner that requires a full table rewrite under an exclusive lock is not an option"。

可以做的是:

  • ALTER TABLE ... ADD COLUMN new_key bigint;。不要不要标记它NOT NULL或给它一个DEFAULT
  • 向 table 添加一个 BEFORE INSERT OR UPDATE ... BEFORE EACH ROW ... 触发器,将整数 ID 列复制到 bigint id 列,例如NEW.new_id := NEW.id
  • 分批,UPDATE将table复制整数键到bigint列,每批后VACUUM
  • 一旦所有新行和现有行都有一个 bigint 键,使用 create unique index ... concurrently 在其上创建一个唯一索引。
  • 创建索引后,添加一个not null 约束。不幸的是,这将进行顺序扫描以验证约束。如果你连这点都不能容忍,有一些技巧可以解决它,但我不准备在 public 中给他们建议,因为你需要 确切地 知道你在做什么这样做是为了安全地进行,并在适当的情况下使用它。
  • begin一个事务,drop触发器,drop旧的主键约束和旧的id列,并在上面添加一个新的主键约束bigint key,指定你并发创建的现有索引作为约束索引,然后commit。这避免了在独占锁下建立索引的需要。

如果 PostgreSQL 支持将 not null 约束添加为 not valid,则此过程会更好,然后让您使用较弱的锁对其进行验证。不幸的是,它还没有这样做。欢迎补丁或其他贡献。

alter table 为 PostgreSQL 9.5 上的某些操作采用的较弱的锁将使您受益匪浅。

理论上 PostgreSQL 可以通过在幕后完成所有这些工作来支持 alter table ... alter type ... concurrently。不过要正确地完成它需要 很多 的工作,所以我预计在不久的将来不会看到一个简单的固定方法。