我们在项目中使用Oracle数据库。我们定义了可以应用于数据库的约束(包括主要,唯一,检查和外键约束)。
似乎定义约束DEFERRABLE允许我们在需要时对它们进行DEFER,那么为什么要将任何约束定义为NOT DEFERRABLE?
为什么像Oracle这样的数据库没有DEFERRABLE作为默认情况?
是否有任何专业人士可以定义约束而不是DEFERRABLE?
答案 0 :(得分:6)
可延迟约束的主要用例是,您不必担心为具有外键关系的多个表执行DML语句的顺序。
考虑以下示例:
create table parent
(
id integer not null primary key
);
create table child
(
id integer not null primary key,
parent_id integer not null references parent
);
create table grand_child
(
id integer not null primary key,
child_id integer not null references child
);
如果约束是立即的,则必须以正确的顺序插入(或删除)行(彼此引用),例如,批量加载数据时出现问题。如果延迟约束,只要在提交事务时一切正常,就可以按任何顺序插入/删除行。
因此,使用可延迟约束(上面的示例不创建!),您可以执行以下操作:
insert into grand_child values (1,1);
insert into child values (1,1);
insert into parent values (1);
commit;
如果约束是立即的,那是不可能的。
以上示例的特例是循环引用:
create table one
(
id integer not null primary key,
id_two integer not null
);
create table two
(
id integer not null primary key
id_one integer not null
);
alter table one add constraint fk_one_two (id_two) references two(id);
alter table two add constraint fk_two_one (id_one) references one(id);
如果不将约束声明为可推迟,则根本无法将数据插入这些表中。
不支持可延迟约束的DBMS的解决方法是使fk列可以为空。然后首先插入空值:
插入一个值(1,null); 插入两个值(1,1); 更新一个 设置id_two = 1 其中id = 1;
使用可延迟约束,您不需要额外的更新语句。
(然而,使用循环参考的设计经常值得怀疑!)
我经常不使用可延迟的约束,但我不想没有它们。
可延迟约束的一个缺点是错误检查。直到commit
您的数据是否正确为止,您才知道。这使得找出出错的有点复杂。如果您在执行insert
(或delete
或update
)时收到错误,则会立即知道哪些值导致错误。