合并多个Oracle触发器。对性能有何影响?

时间:2011-12-20 17:11:44

标签: performance oracle triggers oracle11g

我们的大多数表都有一个BEFORE INSERT OR UPDATE触发器,以便设置ID BEFORE INSERT并设置创建/修改用户/日期BEFORE INSERT OR UPDATE

有几个带有其他触发器的表,它们与前一个触发器分开,以使其意图更加明确。此外,这些附加触发器可以独立于前一个触发器禁用,永远不应禁用。

在大多数情况下,附加触发器也会触发BEFORE INSERT OR UPDATE并且顺序不重要,因为它们涵盖不同的列/用例。所以一般来说,他们可以组合成单个触发器。

是否有关于在桌面上调用1n触发器的速度的研究?或者这与单行插入/更新几乎无关?换句话说,是否只有1个全局SQL -> PL/SQL上下文切换,或者每个触发器将有1个上下文切换。

3 个答案:

答案 0 :(得分:5)

我现在已经对这种情况进行了基准测试,我得出的结论是,当添加1个触发器时,由于PL / SQL上下文切换,很可能会出现严重的性能损失。在我的基准测试中,损失是因子8。然而,添加第二个“兼容”触发器不再具有任何重大影响。通过“兼容”,我的意思是两个触发器总是以任何顺序触发同一事件。

所以我得出的结论是,所有触发器最有可能只有1 SQL -> PL/SQL个上下文切换


这是基准:

创建表

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

...和序列

CREATE SEQUENCE s_test;

典型的触发器设置ID,创建/修改用户/日期

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;

插入1000,10000,100000条记录

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;

结果

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

另一个“兼容”触发器(执行顺序不相关)

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

另一次运行测试脚本的结果

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

停用触发器

alter trigger t_test disable;
alter trigger t_test_other disable;

运行略有不同的测试脚本

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;

结果

-- ------------------------------------
-- +000000000 00:00:00.012712000
-- +000000000 00:00:00.104903000
-- +000000000 00:00:01.043984000
-- ------------------------------------

答案 1 :(得分:1)

我知道在没有触发器和单个触发器之间重做生成存在显着差异,但不是1和n触发器之间的差异。但是,我无法想象没有什么打击,因为SQL和PL / SQL引擎之间会有更多的上下文切换。

答案 2 :(得分:1)

我建议您研究在触发器中使用Sequence的影响 - 在创建序列种子时使用缓存值的序列 (CACHE指定数据库预分配的序列的值数,并保留在内存中以便更快地访问)。我经历过与序列相关的8个因子。在任何情况下,为了比较触发器在上下文切换方面的影响,应该消除序列的使用,或者在评估结果时考虑使用序列。