Oracle
 sql >> Database >  >> RDS >> Oracle

Disattiva i trigger e riattiva i trigger, ma nel frattempo evita l'alterazione della tabella

Un approccio leggermente diverso consiste nel mantenere i trigger abilitati ma ridurne (se non del tutto rimuoverli) l'impatto, aggiungendo un when clausola qualcosa del tipo:

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;
/

Quindi nella tua procedura aggiungi una chiamata al inizia come passaggio "disabilita i trigger":

dbms_application_info.set_client_info('BATCH');

e cancellalo di nuovo alla fine, nel caso in cui la sessione venga lasciata viva e riutilizzata (quindi potresti volerlo fare anche in un gestore di eccezioni):

dbms_application_info.set_client_info(null);

Puoi anche usare il modulo, l'azione o una combinazione. Mentre questa impostazione è attiva, il trigger verrà comunque valutato ma non si attiverà, quindi qualsiasi cosa che accade all'interno verrà saltata:il corpo del trigger non viene eseguito, poiché i documenti mettilo.

Questo non è infallibile in quanto non c'è nulla che impedisca ad altri utenti/applicazioni di fare le stesse chiamate, ma se scegli una stringa più descrittiva e/o una combinazione di impostazioni, dovrebbe essere deliberata - e penso che tu sia principalmente preoccupato per gli incidenti, non per i cattivi attori.

Test rapido della velocità con un trigger inutile che rallenta un po' le cose.

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);

C'è un po' di variazione rispetto all'effettuare chiamate remote, ma ho eseguito alcune volte ed è chiaro che l'esecuzione con un trigger semplice è molto simile all'esecuzione con il trigger vincolato senza BATCH impostato, ed entrambi sono molto più lenti rispetto all'esecuzione senza trigger o con il trigger vincolato con BATCH impostato. Nei miei test c'è una differenza di ordine di grandezza.