Oracle
 sql >> Base de données >  >> RDS >> Oracle

Désactiver les déclencheurs et réactiver les déclencheurs mais éviter de modifier la table entre-temps

Une approche légèrement différente consiste à garder les déclencheurs activés mais à réduire (voire à supprimer entièrement) leur impact, en ajoutant un when clause quelque chose comme :

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

Puis dans votre procédure ajoutez un appel au commencer comme étape "désactiver les déclencheurs" :

dbms_application_info.set_client_info('BATCH');

et effacez-le à nouveau à la fin, juste au cas où la session serait laissée en vie et réutilisée (vous voudrez peut-être également le faire dans un gestionnaire d'exceptions) :

dbms_application_info.set_client_info(null);

Vous pouvez également utiliser module, ou action, ou une combinaison. Tant que ce paramètre est en place, le déclencheur sera toujours évalué mais ne se déclenchera pas, donc tout ce qui se passe à l'intérieur sera ignoré - le corps du déclencheur ne s'exécute pas, car la documentation mettez-le.

Ce n'est pas infaillible car rien n'empêche vraiment d'autres utilisateurs/applications d'effectuer les mêmes appels, mais si vous choisissez une chaîne plus descriptive et/ou une combinaison de paramètres, cela devrait être délibéré - et je pense que vous êtes principalement s'inquiéter des accidents, pas des mauvais acteurs.

Test de vitesse rapide avec un déclencheur inutile qui ne fait que ralentir un peu les choses.

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

Il y a un peu de variation par rapport aux appels à distance, mais j'ai couru plusieurs fois et il est clair que l'exécution avec un déclencheur simple est très similaire à l'exécution avec le déclencheur contraint sans BATCH défini, et les deux sont beaucoup plus lents que l'exécution sans déclencheur ou avec le déclencheur contraint avec BATCH défini. Dans mes tests, il y a une différence d'un ordre de grandeur.