在没有长独占锁

时间:2015-09-21 10:00:51

标签: postgresql postgresql-9.1

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

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

我有一个包含数千个条目的表,其ID为int。现在,ID正在慢慢接近2 ^ 32,我在想是否使用bigint ID创建一个Facade表是合理的,让原始ID继承外观。它有意义吗?

1 个答案:

答案 0 :(得分:5)

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

列类型必须匹配,因为当您查询父表(在ONLY子句中没有FROM)时,PostgreSQL也会隐式扫描子表并附加其结果。如果类型不同,它就不能这样做,就像你可以UNION不同类型的表一样。

根据评论进行更新

使用视图和DO INSTEAD触发器

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

如果您执行UPDATEDELETE,则应该在每个表上定义CHECK约束,将ID的范围限制为非重叠范围,然后决定哪个表根据ID路由DELETEUPDATE

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

会因此而导致性能下降,但您将无需进行全表重写。

逐步更改就地密钥类型

你说更改密钥类型不是一个选项,但你真正想要的是"以一种需要在独占锁下重写完整表的方式更改密钥类型不是选项"

可以做的是:

  • ALTER TABLE ... ADD COLUMN new_key bigint;。请将其标记为NOT NULL或将其设为DEFAULT
  • 向表中添加BEFORE INSERT OR UPDATE ... BEFORE EACH ROW ...触发器,将整数ID列复制到bigint id列,例如NEW.new_id := NEW.id
  • 批量生成,UPDATE将整数键复制到bigint列,并在每批后复制VACUUM
  • 所有新行和现有行都有一个bigint键后,使用create unique index ... concurrently在其上创建一个唯一索引。
  • 创建索引后,添加not null约束。不幸的是,这将进行顺序扫描以验证约束。如果你不能容忍,那么就有黑客可以解决这个问题,但是我并不准备在公共场合为他们提供建议,因为你需要知道完全你所做的事情。要做得安全,并在适当的情况下使用它。
  • begin一个事务,drop触发器,drop旧主键约束和旧id列,并在bigint键上添加新的主键约束,指定您同时创建的现有索引作为约束索引,然后commit。这样就无需在独占锁下构建索引。

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

对于PostgreSQL 9.5上的某些操作,alter table使用较弱的锁会使您受益匪浅。

从理论上讲,PostgreSQL可以通过在幕后完成所有这些来支持alter table ... alter type ... concurrently。尽管如此,正确地做了很多的工作,所以我不希望在不久的将来看到一个简单的罐头方法。