Oracle каскадное удаление - PullRequest
       4

Oracle каскадное удаление

9 голосов
/ 20 декабря 2011

Является ли каскадное удаление в таблице более эффективным, чем отдельные операторы удаления (выполняемые в одном блоке plsql)?

Ответы [ 3 ]

17 голосов
/ 20 декабря 2011

Что делает 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 выдает оператор удаления против CHILD для каждой удаляемой записи в PARENT.

Другой вопрос - какой из двух более эффективен:

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

против

DELETE FROM PARENT WHERE PARENT_ID = 1;

оба с on delete cascade включены. Достаточно удивительно, что в первом вышеприведенном случае Oracle будет проверять индекс внешнего ключа в дочерней таблице, чтобы определить, существуют ли какие-либо строки, для которых требуется каскад. Если строк не существует, Oracle не выполняет каскадное удаление.

6 голосов
/ 20 декабря 2011

Вы не можете сравнить оба варианта, как это. это не проблема производительности, а больше дизайна и структуры.

Если вы разрабатываете свою базу данных с использованием первичных / внешних ключей, будет легче удалить ее с помощью каскадного удаления, чем искать вручную, где у вас есть внешние ключи для столбца и таблицы и генерировать операторы SQL для обработки.

Основным преимуществом функции каскадного удаления является то, что она позволяет вам сократить количество операторов SQL, необходимых для выполнения действий по удалению

0 голосов
/ 20 декабря 2011

Если вы хотите каскадно удалить и у вас не определен внешний ключ, вы можете использовать что-то вроде этого:

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)
     )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...