常見問題--表的約束initially immediate 理解

oracle_db發表於2009-12-10

初始化立即執行--在每條語句執行結束時檢驗約束 

初始化延遲執行--一直等到事務完成後(或者呼叫set constraint immediate語句時)才檢驗約束 

來看下面的程式碼:

SQL> create table t

2 ( x int constraint 
check_x check ( x > 0 ) 
deferrable 
initially immediate,
3 y int constraint 
check_y check ( y > 0 ) 
deferrable 
initially deferred
4 )
5 /
Table created.

SQL> insert into t values ( 1,1 );
1 row created.

SQL> commit;
Commit complete.

所以,當兩個約束同時滿足時才能正確無誤地插入行。但是,如果我試圖插入違反CHECK_X約束(初始化立即執行的約束)的行,則系統會立即檢驗約束,並得到下面的結果:

SQL> insert into t values ( -1,1);

insert into t values ( -1,1)
*
ERROR at line 1:
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_X) violated

由於CHECK_X是可延遲但初始化為立即執行的約束,所以這一行立刻被拒絕了。而CHECK_Y則不同,它不僅是可延遲的,而且初始化為延遲執行,這就意味著直到我用COMMIT命令提交事務或將約束狀態設定為立即執行時才檢驗約束。 

SQL> insert into t values ( 1,-1);
1 row created. 

現在它是成功的(總之到目前為止是成功的)。我將約束檢驗延遲到了執行COMMIT的時候: 

SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_Y) violated

此時資料庫將事務回滾,因為違反約束導致了COMMIT語句的失敗。這些語句說明了初始化立即執行與初始化延遲執行約束之間的區別。initially(初始化)部分指定Oracle什麼時候會進行預設的約束檢驗--是在語句結束時[immediate(立即執行)],還是在事務結束時[deferred(延遲執行)]。我還要說明deferred(可延遲)子句有什麼用。我可以發出命令,讓所有可延遲的約束變為延遲執行的。注意,你也可以對一個約束使用該命令;你不必讓所有可延遲的約束都變為延遲執行的:

SQL> set constraints all deferred;
Constraint set.

SQL> insert into t values ( -1,1);
1 row created. 

由於將初始化立即執行的約束設定為延遲執行的模式,這個語句似乎執行成功;但是,當我用COMMIT語句提交事務時,看一下會發生什麼: 

SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_X) violated 

事務提交失敗並回滾,因為在COMMIT語句之後對約束進行了檢驗。相反,我可以將初始化為延遲執行的約束變為"立即"執行的約束: 

SQL> set constraints all immediate;
Constraint set.

SQL> insert into t values ( 1,-1);
insert into t values ( 1,-1)
*
ERROR at line 1:
ORA-02290: check constraint 
(OPS$TKYTE.CHECK_Y) violated 

前面在我提交前能執行的語句現在立即出了問題。因為我手動修改了預設的約束模式。

延遲約束有哪些實際用處呢? 有很多。它主要用於物化檢視(快照)。這些檢視會使用延遲約束來進行檢視重新整理。在重新整理物化檢視的過程中,可能會破壞完整性,而且將不能逐句檢驗約束。但到執行COMMIT時,資料完整性就沒問題了,而且能滿足約束。沒有延遲約束,物化檢視的約束可能會使重新整理過程不能成功進行。

使用延遲約束的另一個普遍原因是,當預測是否需要更新父/子關係中的主鍵時,它有助於級聯更新。如果你將外來鍵設為可延遲、但初始化為立即執行,那麼你就可以將所有約束設定為可延遲。 

將父鍵更新為一個新值--至此子關係的完整性約束不會被驗證。將子外來鍵更新為這個新值。 COMMIT--只要所有受更新影響的子記錄都指向現有的父記錄,這條命令就能成功執行。

轉:http://www.host01.com/article/database/00060004/0542413042257005.htm

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15720542/viewspace-622173/,如需轉載,請註明出處,否則將追究法律責任。

相關文章