我有以下情况:
表(MyTable
)应该通过批处理(对myplsql()
过程的调用)进行处理(更新/插入/删除等)。
在执行myplsql
期间,任何人都不能触摸MyTable
-因此MyTable
将myplsql
锁定为独占模式。
现在MyTable
定义了多个on insert
,on update
,on delete
触发器,但是在执行批处理时不需要这些触发器-而且它们极大地减慢了批处理的速度。
因此解决方案是在调用myplsql()
之前禁用触发器。
但是如何避免在执行MyTable
之后且alter table ... disable trigger
设法锁定表格之前,有人触摸myplsql
,
假设alter table
执行隐式提交-那么在此之前获得的任何锁都将丢失?
部分问题是我无法控制可能试图触摸表格的其他代码或其他用户。
简而言之,我需要一次完成以下操作:
Lock MyTable
Disable Triggers (somehow without loosing the lock)
Process MyTable
Enable Triggers
Unlock MyTable
一个想法是从表中删除授权-并使其他用户无法使用它。
但事实证明,这不是一个选择,因为其他进程/用户执行以表所有者用户身份登录的操作。
谢谢。
答案 0 :(得分:2)
另一种略有不同的方法是,通过添加when
子句,使触发器保持启用状态,但减小(如果不是完全消除)其影响,
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;
/
然后在您的过程add a call at the start中作为“禁用触发器”步骤:
dbms_application_info.set_client_info('BATCH');
并在最后将其清除,以防万一会话保持活动状态并可以重用(因此,您可能也想在异常处理程序中执行此操作):
dbms_application_info.set_client_info(null);
您也可以使用模块,动作或组合。设置到位后,触发器仍将被评估但不会触发,因此内部发生的任何事情都将被跳过-触发器主体无法运行,如the docs所述。
这并不是万无一失的,因为没有什么可以真正阻止其他用户/应用程序进行相同的调用,但是,如果您选择更具描述性的字符串和/或设置的组合,则必须经过精心设计-我想您大多是担心事故而不是坏演员。
使用无意义的触发器进行快速速度测试,只会使事情放慢一点。
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设置的约束触发器。在我的测试中,存在一个数量级的差异。