sql >> Database >  >> RDS >> Oracle

Schakel triggers uit en schakel triggers opnieuw in, maar vermijd tussentijdse wijziging van de tabel

Een iets andere benadering is om de triggers ingeschakeld te houden, maar hun impact te verminderen (zo niet helemaal te verwijderen) door een when toe te voegen. clausule zoiets als:

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

Voeg vervolgens in uw procedure een aanroep toe aan de begin als uw stap 'triggers uitschakelen':

dbms_application_info.set_client_info('BATCH');

en wis het aan het einde weer, voor het geval de sessie in leven blijft en opnieuw wordt gebruikt (dus misschien wilt u dit ook in een uitzonderingshandler doen):

dbms_application_info.set_client_info(null);

Je zou ook module, of actie, of een combinatie kunnen gebruiken. Terwijl die instelling aanwezig is, wordt de trigger nog steeds geëvalueerd, maar wordt deze niet geactiveerd, dus alles wat er binnen gebeurt, wordt overgeslagen - de trigger wordt niet uitgevoerd, zoals de documenten zet het.

Dit is niet onfeilbaar, want niets weerhoudt andere gebruikers/applicaties er echt van om dezelfde oproepen te doen, maar als je een meer beschrijvende tekenreeks en/of een combinatie van instellingen kiest, zou het weloverwogen moeten zijn - en ik denk dat je meestal bezorgd over ongelukken, geen slechte acteurs.

Snelle snelheidstest met een zinloze trigger die de zaken alleen maar een beetje vertraagt.

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

Er is een beetje variatie in het maken van externe oproepen, maar ik heb een paar keer gerend en het is duidelijk dat hardlopen met een gewone trigger erg lijkt op hardlopen met de beperkte trigger zonder BATCH-set, en beide zijn veel langzamer dan hardlopen zonder een trigger of met de beperkte trigger met BATCH-set. Bij mijn testen is er een verschil in orde van grootte.




  1. MySQL-tool die zoekt naar een string in alle velden, tabellen en databases

  2. asp-serverfout 'Kon bestand of assembly niet laden' maar de assembly is er zeker.

  3. Een database verbinden met Python

  4. SCD-type 2