Consolidate several Oracle triggers. Any performance impact?

前端 未结 3 789
不思量自难忘°
不思量自难忘° 2021-01-12 15:32

Most of our tables have one BEFORE INSERT OR UPDATE trigger, in order to set ID\'s BEFORE INSERT and to set creation / modification users / dates <

相关标签:
3条回答
  • 2021-01-12 16:12

    I would suggest that you investigate the impact of using the Sequence in the trigger - when creating the sequence seed the sequence with a cache value (CACHE specifies how many values of the sequence the database preallocates and keeps in memory for faster access). I have experienced factors far greater the 8 associated with sequences. In any case, in order to compare the impact of a trigger in the terms of context switching the use of the Sequence should be either eliminated for the test or taken into consideration when evaluating the results.

    0 讨论(0)
  • 2021-01-12 16:29

    I know there's a significant difference in redo generation between no triggers and a single trigger, but not about a difference between 1 and n triggers. However, I can't imagine there isnt a hit, as there would be more context switching between the SQL and PL/SQL engines.

    0 讨论(0)
  • 2021-01-12 16:34

    I have now benchmarked this situation and I came to the conclusion that there is a significant performance loss most likely due to PL/SQL context switches, when adding 1 trigger. The loss is by factor 8 in my benchmark. Adding a second "compatible" trigger, however, doesn't have any significant impact anymore. By "compatible", I mean both triggers always fire at the same event in any order.

    So I'm concluding that there is most likely only 1 SQL -> PL/SQL context switch for all triggers


    Here's the benchmark:

    Create a table

    -- A typical table with primary key, creation/modification user/date, and 
    -- other data columns
    CREATE TABLE test(
      id number(38)    not null, -- pk
      uc varchar2(400) not null, -- creation user
      dc date          not null, -- creation date
      um varchar2(400),          -- modification user
      dm date,                   -- modification date
      data number(38)
    );
    

    ... and a sequence

    CREATE SEQUENCE s_test;
    

    A typical trigger setting ID, creation/modification user/date

    CREATE OR REPLACE TRIGGER t_test BEFORE INSERT OR UPDATE
      ON test
      FOR EACH ROW
    BEGIN
      IF inserting THEN
        SELECT s_test.nextval INTO :new.id FROM dual;
    
        :new.uc := USER;
        :new.dc := SYSDATE;
        :new.um := NULL;
        :new.dm := NULL;
      END IF;
      IF updating THEN
        :new.um := USER;
        :new.dm := SYSDATE;
        :new.uc := :old.uc;
        :new.dc := :old.dc;
      END IF;
    END t_test;
    

    Insert 1000, 10000, 100000 Records

    declare
      procedure run (limit number) is
        t timestamp;
      begin
        t := systimestamp;
    
        insert into test (data)
        select level from dual connect by level < limit;
    
        dbms_output.put_line(to_char(systimestamp - t));
    
        rollback;
      end;
    begin
      run(1000);
      run(10000);
      run(100000);
    end;
    

    Results

    -- ------------------------------------
    -- +000000000 00:00:00.086603000
    -- +000000000 00:00:00.844333000
    -- +000000000 00:00:08.429186000
    -- ------------------------------------
    

    Another "compatible" trigger (execution order irrelevant)

    CREATE OR REPLACE TRIGGER t_test_other BEFORE INSERT OR UPDATE
      ON test
      FOR EACH ROW
    BEGIN
      :new.data := 42;
    END t_test_other;
    

    Results of another run of the test script

    -- ------------------------------------
    -- +000000000 00:00:00.088551000
    -- +000000000 00:00:00.876028000
    -- +000000000 00:00:08.731345000
    -- ------------------------------------
    

    Deactivate triggers

    alter trigger t_test disable;
    alter trigger t_test_other disable;
    

    Run a slightly different test script

    declare
      procedure run (limit number) is
        t timestamp;
      begin
        t := systimestamp;
    
        insert into test (id, uc, dc, data)
        select s_test.nextval, user, sysdate, level from dual 
        connect by level < limit;
    
        dbms_output.put_line(to_char(systimestamp - t));
    
        rollback;
      end;
    begin
      run(1000);
      run(10000);
      run(100000);
    end;
    

    Results

    -- ------------------------------------
    -- +000000000 00:00:00.012712000
    -- +000000000 00:00:00.104903000
    -- +000000000 00:00:01.043984000
    -- ------------------------------------
    
    0 讨论(0)
提交回复
热议问题