2011-12-20 11 views
7

¿Es la eliminación en cascada en una tabla más eficiente que las instrucciones de eliminación individuales (ejecutadas en un solo bloque plsql)?Oracle cascade delete

Respuesta

17

Lo que cascade delete hace es emitir sentencias de eliminación individuales.

Examine el siguiente caso de prueba:

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; 

En el archivo de seguimiento, se encuentra una línea como esta:

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 

Eso es Oracle emitir una instrucción de eliminación contra CHILD para cada registro es eliminando en PARENT.

Una cuestión diferente sería cuál de los dos es más eficiente:

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

vs

DELETE FROM PARENT WHERE PARENT_ID = 1; 

ambos con on delete cascade habilitado. Sorprendentemente, en el primer caso anterior, Oracle buscará el índice de clave foránea en la tabla secundaria para ver si existen filas que requieran una cascada. Si no existen filas, Oracle no ejecuta la eliminación en cascada.

+0

+ 1 excelente explicación Adam –

+1

Entonces, ¿dónde está la respuesta? que es mas eficiente – magulla

+0

@magulla: como con la mayoría de las cosas en Oracle, depende. Puede ser más eficiente eliminar manualmente muchas filas secundarias antes de hacer la eliminación, pero nada impide que otra sesión inserte más hijos mientras está sucediendo. Teniendo en cuenta que Oracle emite una eliminación para cada fila primaria eliminada si existen hijos, si el rendimiento es primordial, haga lo posible para eliminar las filas de interés de la tabla hija con una única declaración sería una regla práctica, pero el rendimiento "mejor" no está garantizado. . –

5

No se pueden comparar las dos opciones de este modo. no es un problema de rendimiento, sino más diseño y estructura.

Si diseña su base de datos utilizando claves primarias/externas, será más fácil eliminarla mediante la eliminación en cascada que buscar manualmente dónde tiene claves externas en qué columna y tabla y generar sentencias SQL de mecanizado.

La principal ventaja de la función en cascada-borra es que le permite reducir la cantidad de sentencias SQL que necesita para llevar a cabo acciones de eliminación

0

Si desea eliminar en cascada y no tiene una clave externa definida , puede usar algo como esto:

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

La desventaja de una solución de este tipo sería que cualquier fila insertada que no se vea en la sesión que ejecuta la eliminación seguirá insertándose y quedando huérfana, ya que ha matado al elemento primario, pero las filas secundarias aún se insertan. –

Cuestiones relacionadas