不可推迟与可推迟的初始即时相比

时间:2011-03-14 14:56:05

标签: sql database

我在数据库系统 - 完整的书中读到了关于SQL关键字DEFERRABLE的内容。

  

后者 [NOT DEFERRABLE] 是默认值,表示每次执行数据库修改语句时,如果修改可能违反外键约束,则会立即检查约束。 / p>      

但是,如果我们将约束声明为 DEFERRABLE ,那么我们可以选择让它等到事务完成后再检查约束。

     

我们通过初始延迟初始即时关注关键字 DEFERRABLE 。在前一种情况下,检查将推迟到每个事务提交之前。在后一种情况下,将在每次陈述后立即进行检查。

NOT DEFERRABLEDEFERRABLE INITIALLY IMMEDIATE的区别如何?在这两种情况下,似乎在每个单独的陈述之后都会检查任何约束。

5 个答案:

答案 0 :(得分:57)

使用DEFERRABLE INITIALLY IMMEDIATE,您可以在需要时推迟按需约束。

如果您通常希望在语句时检查约束,但这对于例如批量加载想要将检查推迟到提交时间。

但是,对于各种DBMS,如何推迟约束的语法是不同的。

使用NOT DEFERRABLE,您将永远无法将检查推迟到提交时间。

答案 1 :(得分:27)

除了其他(正确的)答案, 在谈到PostgreSQL 时,必须说明:

  • NOT DEFERRABLE 在插入/更新时检查每一行

  • DEFERRABLE (目前 IMMEDIATE )所有行都会在插入/更新结束时进行检查

  • DEFERRABLE (目前 DEFERRED )所有行都会在交易结束时进行检查

所以这是不正确的,当DEFERRABLE约束设置为IMMEDIATE时,它表现为NOT DEFERRABLE。

让我们详细说明这种差异:

CREATE TABLE example(
    row integer NOT NULL,
    col integer NOT NULL,
    UNIQUE (row, col) DEFERRABLE INITIALLY IMMEDIATE
);

INSERT INTO example (row, col) VALUES (1,1),(2,2),(3,3);

UPDATE example SET row = row + 1, col = col + 1;

SELECT * FROM example;

这正确输出:

output

但是如果我们删除DEFERRABLE INITIALLY IMMEDIATE指令,

  

错误:重复键值违反了唯一约束   “example_row_col_key”DETAIL:键(“row”,col)=(2,2)已经存在。   **********错误**********

     

错误:重复键值违反了唯一约束   “example_row_col_key”SQL状态:23505详细信息:键(“row”,col)=(2,2)   已经存在。

ADDENDUM (2017年10月12日)

此行为确实记录在here,“兼容性”部分:

  

此外,PostgreSQL会立即检查不可延迟的唯一性约束,而不是在标准结束时检查。

答案 2 :(得分:24)

除了能够推迟的明显之外,差异实际上是表现。如果没有性能损失,那么就没有必要选择是否可以推迟 - 所有约束都只是可以推迟的。

在了解数据如何受限的情况下,性能损失与数据库可以执行的优化有关。例如,如果约束是可延迟的,那么为了支持Oracle中的唯一约束而创建的索引不能是唯一索引,因为必须允许临时允许重复。但是,如果约束不可延迟,则索引可以是唯一的。

答案 3 :(得分:3)

我参加聚会很晚了,但我想补充一点-截至2018年12月-只有我知道的两个数据库(可能还有更多)提供该标准SQL功能的某种实现水平

Database    NOT DEFERRABLE  DEFERRABLE           DEFERRABLE 
                            INITIALLY IMMEDIATE  INITIALLY DEFERRED
----------  --------------  -------------------  ------------------
Oracle      N/A *1          Yes (default)        Yes
PostgreSQL  Yes (default)   Yes                  Yes
DB2         -               -                    -
SQL Server  -               -                    -
MySQL       -               -                    -
MariaDB     -               -                    -
SAP Sybase  -               -                    -
HyperSQL    -               -                    -
H2          -               -                    -
Derby       -               -                    -

* 1即使Oracle 12c接受NOT DEFERRABLE 约束状态,它实际上也会忽略它并使它像DEFERRABLE INITIALLY IMMEDIATE一样工作。

如您所见,Oracle没有实现第一种类型(NOT DEFERRABLE),这就是为什么使用Oracle(在本例中为OP)的开发人员可能会感到困惑,并认为前两种类型等效。

有趣的是,Oracle和PostgreSQL具有不同的默认类型。也许对性能有影响。

答案 4 :(得分:2)

NOT DEFERRABLE - 你不能改变约束检查,oracle在每个语句之后检查它(即直接在insert语句之后)。

DEFERRABLE INITIALLY IMMEDIATE - oracle在每个语句后检查约束。但是,您可以在每次交易后(即提交后)将其更改为:

set constraint pk_tab1 deferred;