2011-12-20 9 views

Odpowiedz

17

To, co cascade delete robi, to wydaje indywidualne wyciągi.

zbadania następujących przypadek testowy:

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; 

W pliku śledzenia, można znaleźć linię:

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 

To Oracle wydawania DELETE przeciwko CHILD dla każdego rekordu jest to usuwanie w PARENT.

Innym zagadnieniem, które będzie z nich są bardziej skuteczne:

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

vs

DELETE FROM PARENT WHERE PARENT_ID = 1; 

zarówno on delete cascade włączone. Niespodziewanie, w pierwszym przypadku powyżej, Oracle sonduje indeks klucza obcego na tabeli podrzędnej, aby sprawdzić, czy istnieją wiersze, które wymagałyby kaskady. Jeśli nie ma żadnych wierszy, Oracle nie wykonuje kasowanego usunięcia.

+0

+ 1 doskonałe wyjaśnienie Adam –

+1

więc gdzie jest odpowiedź? co jest bardziej wydajne. – magulla

+0

@magulla: Tak jak w przypadku większości rzeczy w Oracle, to zależy. Ręczne usuwanie wielu wierszy podrzędnych może być skuteczniejsze przed usunięciem, ale nic nie stoi na przeszkodzie, aby inna sesja wstawiała więcej dzieci, gdy to się dzieje. Biorąc pod uwagę, że Oracle wydaje usunięcie dla każdego usuniętego wiersza nadrzędnego, jeśli istnieją dzieci, jeśli wydajność jest najważniejsza, zróbmy wszystko, aby usunąć interesujące wiersze tabeli podrzędnej za pomocą pojedynczej instrukcji, ale "lepsza" wydajność nie jest gwarantowana . –

5

Nie można porównać obu opcji, takich jak ta. nie jest to problem z wydajnością, ale bardziej projekt i struktura.

Jeśli projektujesz bazę danych za pomocą kluczy podstawowych/zagranicznych, łatwiej będzie usunąć za pomocą kaskadowania-usuwania niż wyszukiwanie ręcznie, jeśli masz klucze obce, na których kolumnie i tabeli i generujesz instrukcje SQL.

Główną zaletą funkcji kaskadowych-kasuje jest to, że pozwala zmniejszyć ilość zapytań SQL trzeba wykonać usuwać działań

0

Jeśli chcesz usunąć kaskady i nie mieć klucz obcy zdefiniowane , możesz użyć czegoś takiego:

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

Wadą takiego rozwiązania byłoby to, że wszystkie wstawione wiersze, które sesja, w której usunięto polecenie, nadal będą wstawiane - i osierocone, ponieważ zabiłeś rodzica, ale wiersze podrzędne nadal są wstawiane. –

Powiązane problemy