2011-12-20 281 views

回答

17

什麼cascade delete確實是發出個別刪除語句。

檢查下面的測試案例:

create table parent 
(parent_id number, 
    parent_name varchar2(30), 
    constraint parent_pk primary key (parent_id) using index); 

create table child 
(child_id number, 
    parent_id number, 
    child_name varchar2(30), 
    constraint child_pk primary key (parent_id, child_id) using index, 
    constraint child_fk01 foreign key (parent_id) 
    references parent (parent_id) 
     on delete cascade; 
); 


insert into parent 
(parent_id, parent_name) 
select object_id, object_name from dba_objects where rownum <= 10000; 

begin 
    for i in 1..10 
    loop 
    insert into child 
     (child_id, parent_id, child_name) 
    select i, parent_id, parent_name 
     from parent; 
    end loop; 
end; 
/

exec dbms_stats.gather_table_stats (tabname => 'PARENT', cascade => true); 
exec dbms_stats.gather_table_stats (tabname => 'CHILD', cascade => true); 

exec dbms_monitor.session_trace_enable; 
alter table child drop constraint child_fk01; 
alter table child add constraint child_fk01 foreign key (parent_id) 
    references parent (parent_id) on delete cascade enable novalidate ; 
delete from parent; 
rollback; 

在跟蹤文件,你會發現這樣一行:

delete from "<MY_SCHEMA_NAME>"."CHILD" where "PARENT_ID" = :1 
END OF STMT 
PARSE #6:c=0,e=182,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=1293353992514766 
EXEC#6:c=0,e=545,p=0,cr=2,cu=32,mis=1,r=10,dep=1,og=4,tim=1293353992515354 
EXEC#6:c=0,e=233,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992515644 
EXEC#6:c=0,e=238,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992515931 
EXEC#6:c=0,e=252,p=0,cr=2,cu=32,mis=0,r=10,dep=1,og=4,tim=1293353992516229 
EXEC#6:c=0,e=231,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992516507 
EXEC#6:c=0,e=227,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992516782 
EXEC#6:c=0,e=244,p=0,cr=2,cu=32,mis=0,r=10,dep=1,og=4,tim=1293353992517072 
EXEC#6:c=0,e=219,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992517337 
EXEC#6:c=0,e=236,p=0,cr=3,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992517622 
EXEC#6:c=0,e=235,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992517921 
EXEC#6:c=0,e=229,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992518196 
EXEC#6:c=0,e=246,p=0,cr=2,cu=32,mis=0,r=10,dep=1,og=4,tim=1293353992518487 
EXEC#6:c=0,e=234,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992518767 
EXEC#6:c=6999,e=570,p=0,cr=2,cu=30,mis=0,r=10,dep=1,og=4,tim=1293353992519383 

這是Oracle發出delete語句對CHILD每個它的記錄在PARENT中刪除。

一個不同的問題將是其中的兩個是更有效的:

DELETE FROM CHILD WHERE PARENT_ID = 1; 
DELETE FROM PARENT WHERE PARENT_ID = 1; 

VS

DELETE FROM PARENT WHERE PARENT_ID = 1; 

都與on delete cascade啓用。令人驚訝的是,在上面的第一種情況下,Oracle將在子表上探測外鍵索引,以查看是否存在需要級聯的行。如果不存在行,Oracle不會執行級聯刪除。

+0

+ 1精彩解說Adam – 2011-12-20 19:35:38

+1

那麼答案在哪裏?什麼更有效。 – magulla 2014-06-30 13:11:32

+0

@magulla:與Oracle中的大多數事情一樣,這取決於。在執行刪除操作之前手動刪除多個子行可能會更有效,但是在發生這種情況時,並不會阻止另一個會話插入更多子級。考慮到如果子節點存在,Oracle會刪除每個刪除的父行,如果性能是最重要的,盡最大努力用單個語句刪除子表的相關行將是一條經驗法則,但「更好」的性能不能保證。 – 2015-02-10 15:07:12

5

您不能比較這兩個選項。它不是一個性能問題,而是更多的設計和結構。

如果您使用主鍵/外鍵來設計數據庫,那麼使用級聯刪除將比使用級聯刪除更容易進行刪除,而不是手動搜索哪裏有外鍵在哪個列和表上並生成機械SQL語句。

主要優點的級聯,刪除功能是它可以讓你減少SQL語句需要執行刪除操作

0

如果你想級聯刪除,並沒有定義外鍵的數量,你可以使用像這樣的東西:

DELETE FROM my_table 
WHERE ROWID IN 
    (SELECT ROWID 
     FROM my_table 
     START WITH (condition_on_the_row_that_you_want_to_delete) 
     CONNECT BY PRIOR (primary_key) = (self_foreign_key) 
    ) 
+1

這樣的解決方案的缺點是,插入的任何行會導致您的運行刪除的會話看不到仍然會被插入 - 並且成爲孤兒,因爲您已經殺死了父級,但子級行仍然被插入。 – 2015-01-19 18:37:26