在没有表扫描的情况下向大表添加 NOT NULL 约束

Vol*_*auf 14 postgresql alter-table postgresql-9.3

尝试向NOT NULL具有 10 亿行的表添加约束。我无法承受超过几秒钟的表锁。有没有办法在alter table 语句期间防止全表扫描?我在列上创建了一个索引,希望它能被使用,但这似乎不起作用。可能是检查约束?其他选择?谢谢!

Cra*_*ger 9

有没有办法在alter table 语句期间防止全表扫描?

目前没有支持的、安全的方式来使用 PostgreSQL 来做到这一点。

某种方式ALTER TABLE ... ADD CONSTRAINT ... CONCURRENTLY会很好,但没有人实施它。与添加NOT VALID仍然影响新行的约束的替代方案相同,然后您VALIDATE稍后 - 这会很好,而且每个人都知道这是需要的,但没有人有时间或资金添加。

理论上,如果您知道它是真实有效的,您可以直接修改系统目录以添加约束。实际上,这通常不是一个好主意。

所以不,真的没有办法。

  • 记录:此后为“CHECK”和“FK”约束添加了“NOT VALID”功能。相关:http://dba.stackexchange.com/questions/75613/disable-all-constraints-and-table-checks-while-restoring-a-dump/75635#75635 或 http://dba.stackexchange.com/问题/158499/postgres-how-is-set-not-null-more-efficient-than-check-constraint (4认同)

小智 9

一种可能的替代方法是使用 创建检查约束NOT VALID,然后稍后验证检查约束。这种方法ACCESS EXCLUSIVE只需要在创建约束的持续时间内持有锁,这应该是毫秒级的。该VALIDATE命令将执行耗时的全表扫描以验证约束,但它持有限制性较小的SHARE UPDATE EXCLUSIVE锁。

至于权衡,我一直找不到任何提到标准NOT NULL约束和验证列不为空的检查约束之间的内部机制差异的文档。我记得挖掘了一个论坛帖子,其中没有潜在的性能差异,但丢失了链接,所以这是未经证实的。

ALTER TABLE table ADD CONSTRAINT table_value_not_null_check CHECK (value IS NOT NULL) NOT VALID;

ALTER TABLE table VALIDATE CONSTRAINT table_value_not_null_check;
Run Code Online (Sandbox Code Playgroud)

资料来源:

https://www.postgresql.org/docs/9.4/static/sql-altertable.html https://www.postgresql.org/docs/9.4/static/explicit-locking.html