可延迟外键约束

blu*_*ubb 6 oracle foreign-key constraint

制作外键约束DEFERRABLE INITIALLY IMMEDIATE而不是的后果是什么NONDEFERRABLE

StackOverflow 上的这个答案提到了不再将唯一索引用于可延迟唯一约束所带来的性能影响,我可以与之相关。但是,使外键可延迟有哪些缺点或副作用?

我只能看到一个缺点:早期写入引入的不一致可能在COMMIT发生之前无法检测到。然而,我们的应用程序的存储层将所有 DML 语句延迟到事务结束,因此永远不会读取不一致的 DB 状态(甚至不会被导致它的代码),并且只能在COMMIT任何情况下检测到。

还有其他人吗?

如果重要的话,我们正在考虑在某个表族中制作所有外键DEFERRABLE INITIALLY IMMEDIATE,但只在执行大量相互依赖的插入/更新/的特定作业(大约20 个访问这些表)中延迟它们删除。

TL;DR:我们在制作外键时需要注意DEFERRABLE INITIALLY DEFERRED什么?

Chr*_*xon 2

可延迟约束可以阻止优化器转换。下面是一个简单的示例,验证百分比必须在 0 到 100 之间:

create table exam_results (
  student_id integer, exam_id integer,
  percentage_correct number,
  primary key ( student_id, exam_id )
);

alter table exam_results
  add constraint exre_pct_correct_c
  check ( percentage_correct between 0 and 100 );
Run Code Online (Sandbox Code Playgroud)

通过not deferrable约束,优化器知道如果您搜索超出此范围的值,则查询必须不返回任何行。因此,如果您这样做,可以应用转换来绕过该表:

set serveroutput off

select * from exam_results
where  percentage_correct < 0;

select * 
from   dbms_xplan.display_cursor ( format => 'BASIC +PREDICATE' );

---------------------------------------------------
| Id  | Operation                  | Name         |
---------------------------------------------------
|   0 | SELECT STATEMENT           |              |
|*  1 |  FILTER                    |              |
|*  2 |   TABLE ACCESS STORAGE FULL| EXAM_RESULTS |
---------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(NULL IS NOT NULL)
   2 - storage("PERCENTAGE_CORRECT"<0)
       filter("PERCENTAGE_CORRECT"<0)
Run Code Online (Sandbox Code Playgroud)

请注意,该filter操作NULL IS NOT NULL是完整扫描操作的父操作。因为它是false,所以不需要运行扫描。优化器已完全停止访问表的查询!

如果您将约束重新创建为deferrable,那么您可能会暂时拥有无效数据。即使您声明了它,这也适用initially immediate,因为您可以将状态更改deferred为会话/事务内。

所以优化器不能再依赖约束:

alter table exam_results
  drop constraint exre_pct_correct_c;
  
alter table exam_results
  add constraint exre_pct_correct_c
  check ( percentage_correct between 0 and 100 )
  deferrable initially immediate;

select * from exam_results
where  percentage_correct < 0;

select * 
from   dbms_xplan.display_cursor ( format => 'BASIC +PREDICATE' );

--------------------------------------------------
| Id  | Operation                 | Name         |
--------------------------------------------------
|   0 | SELECT STATEMENT          |              |
|*  1 |  TABLE ACCESS STORAGE FULL| EXAM_RESULTS |
--------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - storage("PERCENTAGE_CORRECT"<0)
       filter("PERCENTAGE_CORRECT"<0)
Run Code Online (Sandbox Code Playgroud)

该计划不再filter有效。数据库读取表中的每一行,检查百分比是否低于零。

TL;DR如果没有经过验证的保证,不可推迟的约束带来的,您就会限制优化器生成更好计划的能力。