sql >> Base de Datos >  >> RDS >> Oracle

Deshabilite los disparadores y vuelva a habilitarlos, pero evite la alteración de la tabla mientras tanto

Un enfoque ligeramente diferente es mantener los disparadores habilitados pero reducir (si no eliminar por completo) su impacto, agregando un when cláusula algo como:

create or replace trigger ...
...
for each row
when (sys_context('userenv', 'client_info') is null
   or sys_context('userenv', 'client_info') != 'BATCH')
declare
...
begin
...
end;
/

Luego, en su procedimiento agregue una llamada al empezar como su paso de 'deshabilitar disparadores':

dbms_application_info.set_client_info('BATCH');

y bórrelo nuevamente al final, en caso de que la sesión quede activa y se reutilice (por lo que es posible que desee hacer esto también en un controlador de excepciones):

dbms_application_info.set_client_info(null);

También puede usar módulo, acción o una combinación. Mientras esa configuración esté en su lugar, el disparador aún se evaluará pero no se disparará, por lo que cualquier cosa que suceda dentro se omitirá:el cuerpo del disparador no se ejecuta, como los documentos ponlo.

Esto no es infalible, ya que no hay nada que realmente impida que otros usuarios/aplicaciones hagan las mismas llamadas, pero si elige una cadena más descriptiva y/o una combinación de configuraciones, tendría que ser deliberado, y creo que en su mayoría está preocupado por los accidentes, no por los malos actores.

Prueba de velocidad rápida con un disparador sin sentido que solo ralentiza un poco las cosas.

create table t42 (id number);

-- no trigger
insert into t42 (id) select level from dual connect by level <= 10000;

10,000 rows inserted.

Elapsed: 00:00:00.050

create or replace trigger tr42 before insert on t42 for each row
declare
  dt date;
begin
  select sysdate into dt from dual;
end;
/

-- plain trigger
insert into t42 (id) select level from dual connect by level <= 10000;

10,000 rows inserted.

Elapsed: 00:00:00.466

create or replace trigger tr42 before insert on t42 for each row
when (sys_context('userenv', 'client_info') is null
   or sys_context('userenv', 'client_info') != 'BATCH')
declare
  dt date;
begin
  select sysdate into dt from dual;
end;
/

-- userenv trigger, not set
insert into t42 (id) select level from dual connect by level <= 10000;

10,000 rows inserted.

Elapsed: 00:00:00.460

- userenv trigger, set to BATCH

exec dbms_application_info.set_client_info('BATCH');

insert into t42 (id) select level from dual connect by level <= 10000;

10,000 rows inserted.

Elapsed: 00:00:00.040

exec dbms_application_info.set_client_info(null);

Hay una pequeña variación con respecto a hacer llamadas remotas, pero ejecuté varias veces y está claro que ejecutar con un disparador simple es muy similar a ejecutar con el disparador restringido sin configurar BATCH, y ambos son mucho más lentos que ejecutar sin un disparador o con el disparador restringido con BATCH establecido. En mis pruebas hay una diferencia de orden de magnitud.