我在数据库系统 - 完整的书中读到了关于SQL关键字DEFERRABLE
的内容。
后者 [NOT DEFERRABLE] 是默认值,表示每次执行数据库修改语句时,如果修改可能违反外键约束,则会立即检查约束。 / p>
但是,如果我们将约束声明为 DEFERRABLE ,那么我们可以选择让它等到事务完成后再检查约束。
我们通过初始延迟或初始即时关注关键字 DEFERRABLE 。在前一种情况下,检查将推迟到每个事务提交之前。在后一种情况下,将在每次陈述后立即进行检查。
NOT DEFERRABLE
与DEFERRABLE INITIALLY IMMEDIATE
的区别如何?在这两种情况下,似乎在每个单独的陈述之后都会检查任何约束。
答案 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;
这正确输出:
但是如果我们删除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;