Então, galera, vocês já estão com aquele conhecimento maneiro sobre triggers, os tipos, como funcionam e até já criaram alguns pra resolver tarefas diferentes. Mas, como sempre rola em programação, saber o que dá pra fazer é importante, mas saber o que NÃO fazer é tão importante quanto. Hoje a gente vai ver os erros clássicos que a galera comete quando mexe com triggers, pra você não cair nessas armadilhas e economizar umas boas horas (ou até dias) de debug.
Recursão de triggers: trigger chamando ela mesma
Esse aqui é, sem dúvida, o erro favorito de quem tá começando. Imagina que você criou uma trigger que atualiza o valor de uma coluna da tabela, tipo last_modified. Só que assim que esse update rola, a própria operação dispara de novo a trigger. Isso vira um loop infinito e, no fim, seu servidor cai com erro de stack overflow.
Exemplo:
CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
-- Atualizando o campo last_modified
UPDATE my_table
SET last_modified = NOW()
WHERE id = NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER after_update
AFTER UPDATE ON my_table
FOR EACH ROW
EXECUTE FUNCTION update_last_modified();
O que tá errado aqui? O UPDATE dentro da função chama a mesma trigger que criou ela. Pronto, temos um loop infinito.
Como evitar:
Usa a variável OLD e compara os valores antes de fazer qualquer alteração:
CREATE OR REPLACE FUNCTION update_last_modified_safe()
RETURNS TRIGGER AS $$
BEGIN
-- Checa se o valor mudou
IF NEW.last_modified IS DISTINCT FROM OLD.last_modified THEN
NEW.last_modified = NOW();
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Se liga pra não fazer operações desnecessárias dentro da trigger.
Uso errado de OLD e NEW
Essas variáveis são tipo melhores amigos quando você mexe com triggers, mas na mão de quem tá começando podem virar uma dor de cabeça. OLD guarda os dados antes da alteração da linha, e NEW são os dados que vão ser salvos depois da alteração.
O erro rola quando você interpreta errado ou tenta usar essas variáveis onde elas não existem. Por exemplo, se você tá num trigger BEFORE INSERT, o OLD não existe — afinal, a linha tá sendo criada agora.
Exemplo de erro:
-- Isso vai dar erro porque OLD não existe no insert
CREATE OR REPLACE FUNCTION log_inserts()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (old_data, new_data)
VALUES (OLD.my_column, NEW.my_column);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Como evitar:
Presta atenção onde usar OLD e NEW:
OLDtá disponível em operaçõesUPDATEeDELETE.NEWtá disponível em operaçõesINSERTeUPDATE.
Vários triggers pra uma operação só
No PostgreSQL, dá pra criar vários triggers pra mesma operação e tabela. Parece prático, mas na real isso pode virar uma bagunça se os triggers começarem a brigar entre si ou mexerem nos mesmos dados.
Exemplo:
-- Trigger 1
CREATE OR REPLACE FUNCTION trigger_one()
RETURNS TRIGGER AS $$
BEGIN
-- Lógica do trigger 1
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger 2
CREATE OR REPLACE FUNCTION trigger_two()
RETURNS TRIGGER AS $$
BEGIN
-- Lógica do trigger 2
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Criando dois triggers
CREATE TRIGGER trigger_one AFTER INSERT ON my_table EXECUTE FUNCTION trigger_one();
CREATE TRIGGER trigger_two AFTER INSERT ON my_table EXECUTE FUNCTION trigger_two();
Os dois triggers vão rodar quando inserir uma linha na tabela my_table. Se a lógica deles não estiver bem sincronizada, pode dar resultado estranho.
Como evitar:
- Pensa na arquitetura dos triggers antes de sair criando.
- Se os triggers fazem parte da mesma lógica, junta tudo em um só.
Problemas de performance
Triggers adicionam processamento extra pra cada operação que eles acompanham. Se você usa triggers em tabelas com muita operação ou muitos registros, pode acabar derrubando a performance do banco.
Exemplo ruim:
CREATE OR REPLACE FUNCTION heavy_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
-- Operação pesada rodando em todo update de linha
PERFORM some_heavy_query();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER performance_killer AFTER UPDATE ON huge_table EXECUTE FUNCTION heavy_trigger_function();
Como evitar:
- Deixa a lógica do trigger o mais leve possível. Se precisar rodar algo pesado, tenta jogar pra uma tarefa em background.
- Usa restrições pra rodar o trigger só quando precisa, com a condição
WHEN:
CREATE TRIGGER optimized_trigger
AFTER UPDATE ON my_table
WHEN (OLD.column_name IS DISTINCT FROM NEW.column_name)
EXECUTE FUNCTION light_function();
Triggers e transações
Triggers rodam dentro da transação que seu comando iniciou. Se rolar um erro dentro do trigger, a transação inteira é desfeita. Isso pode ser útil em alguns casos, mas pode dar dor de cabeça se você não pensar bem no tratamento de erros.
Exemplo de erro:
CREATE OR REPLACE FUNCTION error_prone_trigger()
RETURNS TRIGGER AS $$
BEGIN
-- Criando um erro
RAISE EXCEPTION 'Algo deu errado!';
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Se esse trigger rodar, a transação do seu comando principal vai ser desfeita.
Como evitar:
Coloca tratamento de erro nos triggers pra não ferrar a transação principal:
CREATE OR REPLACE FUNCTION safe_trigger()
RETURNS TRIGGER AS $$
BEGIN
BEGIN
-- Código que pode dar erro
INSERT INTO another_table VALUES (NEW.data);
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Rolou um erro, mas a gente tratou de boa.';
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Dicas práticas
Deixe os triggers o mais simples possível. Se você achar que o trigger tá ficando grande ou complicado demais, talvez seja melhor dividir em funções menores ou repensar a lógica.
Sempre teste triggers com poucos dados primeiro. Antes de colocar o trigger numa tabela importante, testa ele num ambiente de teste com poucos registros.
Documente seus triggers. Daqui a uns meses, você ou alguém do seu time pode não lembrar porque aquele trigger existe. Uma documentação clara evita muita dor de cabeça.
Evite triggers pra tarefas que podem ser resolvidas na aplicação. Triggers são ótimos pra automatizar tarefas que precisam ser instantâneas, mas usar pra lógica de negócio complexa pode dar problema no futuro.
Fique de olho na performance. Sempre monitore o impacto dos triggers na performance do banco, principalmente se o volume de dados ou a carga aumentar.
Com essas dicas e o que você aprendeu hoje, você tá pronto não só pra criar triggers, mas pra fazer triggers que funcionam direitinho, são eficientes e não vão te dar susto depois.
GO TO FULL VERSION