sql >> Databasteknik >  >> RDS >> Oracle

Inaktivera utlösare och återaktivera utlösare men undvik tabelländringar under tiden

Ett lite annorlunda tillvägagångssätt är att hålla triggarna aktiverade men minska (om inte helt ta bort) deras inverkan, genom att lägga till en when klausul något som:

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

Sedan i din procedur lägg till ett samtal på starta som ditt "inaktivera triggers"-steg:

dbms_application_info.set_client_info('BATCH');

och rensa den igen i slutet, ifall sessionen lämnas vid liv och återanvänds (så du kanske vill göra detta i en undantagshanterare också):

dbms_application_info.set_client_info(null);

Du kan också använda modul, handling eller en kombination. Medan den inställningen är på plats kommer triggern fortfarande att utvärderas men kommer inte att aktiveras, så allt som händer inuti kommer att hoppas över - triggerkroppen körs inte, eftersom dokumenten uttryck det.

Detta är inte idiotsäkert eftersom det inte finns något som verkligen hindrar andra användare/applikationer från att ringa samma samtal, men om du väljer en mer beskrivande sträng och/eller en kombination av inställningar måste det vara avsiktligt - och jag tror att du oftast är orolig för olyckor inte dåliga skådespelare.

Snabbt hastighetstest med en meningslös trigger som bara saktar ner något.

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

Det finns lite variation från att ringa fjärrsamtal, men jag sprang några gånger och det är tydligt att att springa med en vanlig trigger är väldigt lik att springa med den begränsade triggern utan BATCH-uppsättning, och båda är mycket långsammare än att springa utan en trigger eller med den begränsade utlösaren med BATCH inställd. I mina tester finns det en storleksskillnad.




  1. Ändra decimalavgränsare i MySQL

  2. Hur beräknar jag arean av en polygon i en MySQL-databas när polygonens punkter är lat långa?

  3. Skapa ett Excel-kalkylblad från en Oracle-databas

  4. MySQL:Automatisk ökning av temporär kolumn i select-satsen