Mais cedo ou mais tarde, muitos enfrentam a necessidade de consertar massivamente algo nas entradas da tabela. Eu já disse como fazê-lo melhor e como - é melhor não fazê-lo. Hoje vou falar sobre o segundo aspecto da atualização em massa - acionar gatilhos .Por exemplo, em uma tabela na qual você precisa consertar algo, um gatilho maligno trava ON UPDATE
, transferindo todas as alterações para alguns agregados. E você precisa atualizar tudo (inicialize um novo campo, por exemplo) com tanto cuidado para que essas unidades não sejam afetadas.Vamos desligar os gatilhos!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Na verdade, é tudo - tudo já está pendurado .Porque ALTER TABLE
impõe um bloqueio AccessExclusive , sob o qual ninguém executando em paralelo, mesmo um simples SELECT
, pode ler qualquer coisa da tabela. Ou seja, até que essa transação seja concluída, todos que quiserem “apenas ler” aguardarão. E lembramos que UPDATE
fazemos o-o-olgi ...Vamos desligá-lo rapidamente e ligá-lo rapidamente!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Aqui a situação é melhor, o tempo de espera é muito menor. Mas apenas dois problemas estragam toda a beleza:ALTER TABLE
ele espera por todas as outras operações na mesa, incluindo longas SELECT
- Enquanto o gatilho estiver desligado, qualquer alteração na tabela passará , nem mesmo a nossa. E bem, ele não entra nas unidades, embora deva. Problema!
Gerenciamento de variável de sessão
Portanto, na versão anterior, deparamos com um ponto crucial - precisamos ensinar de alguma forma o gatilho para distinguir “nossas” alterações na tabela de “não nossas”. Pule "o nosso" como está, mas "não o nosso" - gatilho. Você pode usar variáveis de sessão para isso .session_replication_role
Leia o manual :A variável acionadora também é afetada pela variável de configuração session_replication_role . Os gatilhos ativados sem instruções adicionais (padrão) serão acionados quando a função de replicação for "origem" (padrão) ou "local". Os acionadores ativados por uma indicação ENABLE REPLICA
serão acionados apenas se o modo de sessão atual for "réplica", e os acionadores ativados por uma indicação ENABLE ALWAYS
serão acionados independentemente do modo de replicação atual.
Enfatizo que a configuração não se aplica a todos de uma vez ALTER TABLE
, mas apenas à nossa conexão especial separada. Total para que nenhum aplicativo inicie o disparo:SET session_replication_role = replica;
UPDATE ...;
SET session_replication_role = DEFAULT;
Condição dentro do gatilho
Mas a opção acima funciona para todos os gatilhos de uma só vez (ou você precisa "acionar" gatilhos com antecedência que não deseja desativar). E se precisarmos "desligar" um gatilho específico ?A variável de sessão "user" nos ajudará com isso :Os nomes dos parâmetros de extensão são escritos da seguinte forma: nome da extensão, período e, em seguida, o próprio nome do parâmetro, como os nomes completos dos objetos no SQL. Por exemplo: plpgsql.variable_conflict.
Como os parâmetros que não são do sistema podem ser definidos em processos que não carregam o módulo de extensão correspondente, o PostgreSQL aceita valores para qualquer nome com dois componentes .
Primeiro, modifique o gatilho, algo como isto:BEGIN
IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
IF TG_OP IN ('INSERT', 'UPDATE') THEN
RETURN NEW;
ELSE
RETURN OLD;
END IF;
END IF;
...
A propósito, isso pode ser feito "lucrativamente", sem bloqueios, através CREATE OR REPLACE
de uma função de gatilho. E então, na conexão especial, tornamos a variável "nossa":
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = '';
Você conhece outras maneiras? Compartilhe nos comentários.