为什么 PostgreSQL 在每个语句后检查 DEFERRABLE INITIALLY IMMEDIATE 约束?

问题描述 投票:0回答:2

我运行以下 SQL,但从未提交事务:

rollback;
begin;
create table testing_stuff (
    id serial,
    num integer NOT NULL unique deferrable initially immediate
);

insert into testing_stuff (num) values (2), (1);

-- no issues with deferrable even though it swaps values
update testing_stuff set num = id;

-- fails even though I have not comitted;
update testing_stuff set num = 2;

-- this would have fixed it
update testing_stuff set num = id;

如果我删除

deferrable initially immediate
那么它会在
update testing_stuff set num = id;
上失败,因为每一行都会立即检查。所以
deferrable initially immediate
肯定是在推迟一些事情。

我的理解是,由于事务未提交,所以这里根本不应该检查任何约束,基于SET CONSTRAINTS文档,其中说:

DEFERRED 约束在事务提交之前不会被检查。

如果我删除线

update testing_stuff set num = 2;
,那么一切都会正常。 另外,如果我使用
deferrable initially deferred
那么我会得到我期望的延迟行为。

我对交易边界和/或

initially immediate
缺少什么?
initially immediate
是否也适用于交易中的所有 future 语句?但为什么
deferrable initially immediate
会避免
update testing_stuff set num = id;
上的错误呢?

postgresql unique-constraint deferrable-constraint
2个回答
0
投票

这里有两件事在起作用:

  1. DEFERRABLE
    不是
    DEFERRED
    INITIALLY IMMEDIATE
    部分意味着约束不是 在事务结束时检查,而是在每个语句之后检查。您需要编写
    DEFERRABLE INITIALLY DEFERRED
    让 PostgreSQL 在事务结束时检查约束。

  2. DEFERRABLE
    约束的实现方式与 PostgreSQL 中的
    NOT DEFERRABLE
    约束(默认)不同。

    NOT DEFERRABLE
    将行插入到唯一索引时会验证唯一约束,因此当交换两个值时,更改第一行会触发约束违规。

    DEFERRABLE
    唯一约束是通过在语句末尾执行的系统触发器来实现的,因此使用
    DEFERRABLE
    约束不会违反约束,因为在语句交换值后数据是一致的。

    默认的

    NOT DEFERRABLE
    行为不符合SQL标准的定义,它要求在语句之后检查约束。 PostgreSQL 的默认行为是出于性能原因;如果您需要严格遵守标准,请使用
    DEFERRABLE
    约束。


0
投票

如果违反约束,则会引发异常

  • 交易结束时如果约束是
    deferrable initially deferred
  • 语句的末尾(如果是
    deferrable initially immediate
  • 中间陈述如果是
    not defferable

名称中带有

immediate
的选项实际上是总体约束验证方面第二个最直接的选项,仅在两个
deferrable
中是第一个最直接的,我猜这就是该语法的来源。
所有约束都会在现场立即得到真正的检查。不同之处在于,常规的、不可推迟的一旦发现违规行为就会提出异常,而可推迟的只会在稍后重新检查。

create table
alter table..disable trigger
set constraints
文档条目的约束部分对此不是很清楚,而且immediate的不同含义使情况变得更糟。 64.5。索引唯一性检查更有帮助(这里,立即实际上意味着立即):

UNIQUE_CHECK_YES
表示这是一个不可延迟的唯一索引,并且必须立即进行唯一性检查,如上所述。

UNIQUE_CHECK_PARTIAL
表示唯一约束是可延迟的。 PostgreSQL将使用这种模式来插入每行的索引条目。访问方法必须允许重复条目进入索引,并通过从 aminsert 返回 false 来报告任何潜在的重复项。对于返回 false 的每一行,将安排延迟重新检查。

UNIQUE_CHECK_EXISTING
表示这是对报告为潜在唯一性违规的行的延迟重新检查。

来源中的评论也非常有帮助:

这可能是语句结束检查、提交时检查或由 SET CONSTRAINTS 命令触发的检查。

但前提是您记住默认值是真正立即的,中间语句并且它指的是计划的重新检查。基础检查仍然是立即进行的。

© www.soinside.com 2019 - 2024. All rights reserved.