Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Deaktivieren Sie Trigger und aktivieren Sie Trigger erneut, aber vermeiden Sie in der Zwischenzeit Tabellenänderungen

Ein etwas anderer Ansatz besteht darin, die Auslöser aktiviert zu lassen, aber ihre Auswirkungen zu reduzieren (wenn nicht ganz zu entfernen), indem ein when hinzugefügt wird Klausel etwas wie:

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

Fügen Sie dann in Ihrer Prozedur einen Aufruf an der hinzu starten als Schritt „Auslöser deaktivieren“:

dbms_application_info.set_client_info('BATCH');

und löschen Sie es am Ende wieder, nur für den Fall, dass die Sitzung am Leben bleibt und wiederverwendet wird (also möchten Sie dies vielleicht auch in einem Ausnahmehandler tun):

dbms_application_info.set_client_info(null);

Sie könnten auch Modul oder Aktion oder eine Kombination davon verwenden. Während diese Einstellung vorhanden ist, wird der Trigger weiterhin ausgewertet, aber nicht ausgelöst, sodass alles, was im Inneren passiert, übersprungen wird – der Triggerkörper wird nicht ausgeführt, da die Dokumentation sagen.

Dies ist nicht narrensicher, da nichts wirklich andere Benutzer/Anwendungen davon abhält, die gleichen Anrufe zu tätigen, aber wenn Sie eine aussagekräftigere Zeichenfolge und/oder eine Kombination von Einstellungen auswählen, müsste dies absichtlich sein – und ich denke, Sie sind es meistens besorgt über Unfälle keine schlechten Schauspieler.

Schneller Geschwindigkeitstest mit einem sinnlosen Auslöser, der die Dinge nur ein wenig verlangsamt.

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

Es gibt eine kleine Variation von Remote-Aufrufen, aber ich bin ein paar Mal gelaufen und es ist klar, dass das Ausführen mit einem einfachen Trigger dem Ausführen mit dem eingeschränkten Trigger ohne BATCH-Set sehr ähnlich ist, und beide sind viel langsamer als das Ausführen ohne Trigger oder mit der eingeschränkte Trigger mit BATCH-Set. In meinen Tests gibt es einen Unterschied von einer Größenordnung.