2011-10-26 89 views
1

說我有兩個表:甲骨文刪除性能

create table parent (
    id number not null, 
    constraint parent_pk primary key(id), 
) 

create table child (
    id number not null, 
    parent_id number not null, 
    constraint child_pk primary key(id), 
    constraint child_fk1 foreign key(parent_id) 
    references parent(id) 
) 

父表是很大的,比如說,300萬的記錄。現在我運行刪除語句:

delete from parent; //even without where clause 

請您解釋執行此語句時實際發生了什麼?哪裏沒有指定「ON DELETE CASCADE」選項,據我所知,這意味着如果子表包含對父ID的引用,則從父表中刪除應該失敗。所以這意味着在從父表中刪除行之前,Oracle應該檢查是否存在任何子記錄。但這真的非常慢 - 它是逐行刪除。

我正確嗎?如果沒有,請解釋從父表中刪除時Oracle是如何工作的,並檢查子表中是否還有孤兒?

+0

我認爲你是對的。這是一個逐行檢查。 ON DELETE CASCADE不應該失敗,但是也應該刪除子行。 – Thilo

+0

這是否意味着ON DELETE CASCADE的性能與沒有此選項時大致相同? (考慮到沒有引用子表的表) – andrershov

+0

當你說「但是這真的非常慢 - 它是逐行刪除。「你的意思是你已經運行了一個測試用例,它真的很慢*?或者你只是想象得到這樣的結果嗎? – APC

回答

7

這是一個測試。我的PARENT表有100000行。對一個空的子表(與PARENT_ID索引)刪除這個長鏡頭:

SQL> set timing on 
SQL> delete from parent; 

100000 rows deleted. 

Elapsed: 00:00:07.24 
SQL> 

讓我們插入一些行到孩子。這將在父母身上產生一排每行

SQL> insert into child 
    2 select level, level from dual 
    3 connect by level <= 100000; 


100000 rows created. 

Elapsed: 00:00:02.21 
SQL> 

如果我們現在從父母中刪除,它會立即失敗。

SQL> delete from parent; 
delete from parent 
* 
ERROR at line 1: 
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found 


Elapsed: 00:00:00.14 
SQL> 

然而,如果我們家長有充分的紀錄CHILD點只是一個記錄它需要更長的時間......

SQL> update child set parent_id=99999; 

100000 rows updated. 

Elapsed: 00:00:09.65 
SQL> commit; 

SQL> delete from parent; 
delete from parent 
* 
ERROR at line 1: 
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found 


Elapsed: 00:00:07.32 

掛鐘定時是非常不可靠的,但看起來像大致相同的時間。而且,因爲它發生,刪除父表沒有外鍵依賴的時間是在同一個球場:

SQL> drop table child; 

Table dropped. 

Elapsed: 00:00:02.29 
SQL> delete from parent; 

100000 rows deleted. 

Elapsed: 00:00:06.54 
SQL> 

所以,基本上,很少或沒有開銷檢查外鍵約束

有是條件:這是真的提供的外鍵列索引爲。我放棄了CHILD_FK1_I索引,並且在我輸入此響應的時間內(即大約十分鐘),該語句仍未完成。

+0

哦,那太好了。你能否也請看看[這個問題](http://stackoverflow.com/questions/7902473/oracle-bottom-up-delete)? – andrershov

1

由於您的子表在parent_id上沒有索引,因此每次需要檢查子項的存在時,oracle都會強制進行全面掃描。另一個問題是,當您計劃用多個進程執行此操作時,缺少此索引可能會引發爭用。如果沒有對parent_id進行索引,那麼子表將獲得表鎖,通常只有一行將被鎖定。

除此之外,給數據庫命令刪除一行是最糟糕的命令來執行。如果你看看水下會發生什麼(撤消,重做等),它是一切都很快...

+0

好吧,例如我爲parent_id創建了索引。Oracle如何確定是否沒有孩子行參考父行在這種情況下? – andrershov

+0

什麼意思與'最可能的命令'? –

+0

@andrershov它會很快,但如果你必須做很多行這樣做,你可能會考慮禁用約束並啓用它之後 –