如何在不锁定表的情况下在 Postgres 中添加检查约束?

Kev*_*rke 13 postgresql constraint data-integrity

我想向一个非常大的表添加一个检查约束。就像是:

ALTER TABLE "accounts" ADD CONSTRAINT "positive_balance" CHECK ("balance" >= 0);
Run Code Online (Sandbox Code Playgroud)

不幸的是 PostgreSQL 9.3 在约束检查完成之前阻止读取或写入。我通过启动一个事务,运行ALTER TABLE,然后打开第二个事务并检查在第一个事务完成之前我无法从表中读取或写入来验证这一点。

有什么办法可以在CHECK不锁定表的情况下添加此约束?

Joi*_*dio 14

您可以创建一个NOT VALIDCHECK 约束,它将强制执行该约束,但不会在创建时检查整个表以进行验证。在以后的某个日期,您可以尝试VALIDATE约束(当表上的锁没问题时)

请查看文档- 引用如下:

ADD table_constraint [ NOT VALID ]

这种形式使用与 相同的语法向表添加一个新约束CREATE TABLE,加上选项NOT VALID,目前仅允许用于外键和 CHECK 约束。如果约束被标记为NOT VALID,则跳过可能冗长的初始检查以验证表中的所有行是否满足约束。该约束仍将针对后续插入或更新强制执行(也就是说,除非引用表中有匹配的行,否则它们将失败,在外键的情况下;除非新行与指定的检查匹配,否则它们将失败约束)。但是数据库不会假设约束对表中的所有行都成立,直到使用该VALIDATE CONSTRAINT选项对其进行验证。


小智 10

(没有足够的代表对另一个答案发表评论)

从接受的答案中的措辞中不清楚“当桌子上的锁正常时”是什么意思。

根据 Postgres ALTER TABLE 文档

VALIDATE CONSTRAINTSHARE UPDATE EXCLUSIVE在改变后的桌子上抓起一个,

和来自锁定文档

SHARE UPDATE EXCLUSIVE允许其他并发事务获取ROW EXCLUSIVE锁(由INSERT, UPDATE, 使用DELETE),并且SELECT允许使用除 之外的任何锁类型ACCESS EXCLUSIVE

意思是——“读/写”在运行时不会被阻塞VALIDATE CONSTRAINT——你不需要“等到可以锁定表”。

  • 在撰写本文时(PostgreSQL 9.3),“VALIDATE CONSTRAINT”获取了“ACCESS EXCLUSIVE”锁。然而,这对于未来的读者和版本来说是很好的信息。我的 +1 (5认同)