Nieco innym podejściem jest pozostawienie włączonych wyzwalaczy, ale zmniejszenie (jeśli nie całkowite usunięcie) ich wpływu, poprzez dodanie when
klauzula coś w stylu:
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;
/
Następnie w procedurze dodaj połączenie na start jako krok „wyłącz wyzwalacze”:
dbms_application_info.set_client_info('BATCH');
i wyczyść go ponownie na końcu, na wypadek gdyby sesja pozostała aktywna i ponownie wykorzystana (więc możesz to zrobić również w obsłudze wyjątków):
dbms_application_info.set_client_info(null);
Możesz także użyć modułu, akcji lub kombinacji. Gdy to ustawienie jest włączone, wyzwalacz będzie nadal oceniany, ale nie zostanie uruchomiony, więc wszystko, co dzieje się w środku, zostanie pominięte - ciało wyzwalacza nie zostanie uruchomione, ponieważ dokumentacja połóż to.
Nie jest to niezawodne, ponieważ nic tak naprawdę nie powstrzymuje innych użytkowników/aplikacji przed wykonywaniem tych samych połączeń, ale jeśli wybierzesz bardziej opisowy ciąg i/lub kombinację ustawień, będzie to musiało być celowe – i myślę, że głównie martwi się o wypadki, a nie źli aktorzy.
Szybki test prędkości z bezsensownym wyzwalaczem, który tylko trochę spowalnia.
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);
Istnieje pewna różnica w stosunku do wykonywania połączeń zdalnych, ale uruchomiłem kilka razy i jasne jest, że bieganie ze zwykłym wyzwalaczem jest bardzo podobne do uruchamiania z ograniczonym wyzwalaczem bez ustawionego polecenia BATCH, a oba są znacznie wolniejsze niż uruchamianie bez wyzwalacza lub z ograniczony wyzwalacz z ustawionym BATCH. W moich testach jest różnica rzędu wielkości.