定义约束可延迟的缺点和优点是什么

时间:2013-12-07 09:43:31

标签: sql oracle database-design constraints

我们在项目中使用Oracle数据库。我们定义了可以应用于数据库的约束(包括主要,唯一,检查和外键约束)。

似乎定义约束DEFERRABLE允许我们在需要时对它们进行DEFER,那么为什么要将任何约束定义为NOT DEFERRABLE?

为什么像Oracle这样的数据库没有DEFERRABLE作为默认情况?

是否有任何专业人士可以定义约束而不是DEFERRABLE?

1 个答案:

答案 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(或deleteupdate)时收到错误,则会立即知道哪些值导致错误。