且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

禁用触发器并重新启用触发器,但同时避免更改表

更新时间:2023-02-03 20:05:27

一种稍有不同的方法是通过添加when子句,使触发器保持启用状态,但减小(如果不是完全消除)其影响,请执行以下操作:

A slightly different approach is to keep the triggers enabled but reduce (if not quite entirely remove) their impact, by adding a when clause something like:

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

然后在您的过程中添加呼叫一开始作为禁用触发器"步骤:

Then in your procedure add a call at the start as your 'disable triggers' step:

dbms_application_info.set_client_info('BATCH');

并在最后将其清除,以防万一会话保持活动状态并被重用(因此,您可能也想在异常处理程序中执行此操作):

and clear it again at the end, just in case the session is left alive and reused (so you might want to do this in an exception handler too):

dbms_application_info.set_client_info(null);

您还可以使用模块,操作或组合.设置到位后,触发器仍将被评估但不会触发,因此内部发生的任何事情都将被跳过-触发器主体不运行,如

You could also use module, or action, or a combination. While that setting is in place the trigger will still be evaluated but won't fire, so any thing happening inside will skipped - the trigger body does not run, as the docs put it.

这并不是万无一失的,因为没有什么可以真正阻止其他用户/应用程序进行相同的调用,但是,如果您选择更具描述性的字符串和/或设置的组合,则必须进行仔细考虑-我想您大多是担心事故而不是坏演员.

This isn't foolproof as there is nothing really stopping other users/applications making the same calls, but if you pick a more descriptive string and/or a combination of settings, it would have to be deliberate - and I think you're mostly worried about accidents not bad actors.

使用无意义的触发器进行快速速度测试,只会使事情放慢一点.

Quick speed test with a pointless trigger that does just slows things down a bit.

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

进行远程调用有一些差异,但我跑了几次,很明显,使用普通触发器运行与不设置BATCH的受限触发器运行非常相似,并且两者都比不使用BATCH进行运行要慢得多触发或设置了BATCH的约束触发.在我的测试中,存在一个数量级的差异.

There's a bit of variation from making remote calls, but I ran a few times and it's clear that running with a plain trigger is very similar to running with the constrained trigger without BATCH set, and both are much slower than running without a trigger or with the constrained trigger with BATCH set. In my testing there's an order of magnitude difference.