Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Desative gatilhos e reative gatilhos, mas evite a alteração da tabela nesse meio tempo


Uma abordagem um pouco diferente é manter os gatilhos ativados, mas reduzir (se não remover totalmente) seu impacto, adicionando um when cláusula algo como:
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;
/

Em seguida, em seu procedimento adicione uma chamada no iniciar como sua etapa de 'desativar acionadores':
dbms_application_info.set_client_info('BATCH');

e limpe-o novamente no final, caso a sessão seja deixada ativa e reutilizada (então você pode querer fazer isso em um manipulador de exceção também):
dbms_application_info.set_client_info(null);

Você também pode usar módulo, ação ou uma combinação. Enquanto essa configuração estiver em vigor, o gatilho ainda será avaliado, mas não será acionado, portanto, qualquer coisa que aconteça dentro dele será ignorada - o corpo do gatilho não é executado, pois os documentos colocá-lo.

Isso não é infalível, pois nada impede que outros usuários/aplicativos façam as mesmas chamadas, mas se você escolher uma string mais descritiva e/ou uma combinação de configurações, teria que ser deliberado - e acho que você está principalmente preocupado com acidentes não maus atores.

Teste rápido de velocidade com um gatilho inútil que apenas retarda um pouco as coisas.
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);

Há um pouco de variação de fazer chamadas remotas, mas eu corri algumas vezes e está claro que executar com um gatilho simples é muito semelhante a executar com o gatilho restrito sem o conjunto BATCH, e ambos são muito mais lentos do que executar sem um gatilho ou com o gatilho restrito com o conjunto BATCH. Nos meus testes, há uma diferença de ordem de magnitude.