CodeGym /Cursos /SQL SELF /Análise dos erros mais comuns no desenvolvimento de trigg...

Análise dos erros mais comuns no desenvolvimento de triggers

SQL SELF
Nível 58, Lição 4
Disponível

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:

  • OLD tá disponível em operações UPDATE e DELETE.
  • NEW tá disponível em operações INSERT e UPDATE.

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

  1. 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.

  2. Sempre teste triggers com poucos dados primeiro. Antes de colocar o trigger numa tabela importante, testa ele num ambiente de teste com poucos registros.

  3. 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.

  4. 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.

  5. 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.

2
Tarefa
SQL SELF, nível 58, lição 4
Bloqueado
Criação de um trigger seguro para atualizar uma coluna
Criação de um trigger seguro para atualizar uma coluna
1
Pesquisa/teste
Triggers em nível de linha e tabela, nível 58, lição 4
Indisponível
Triggers em nível de linha e tabela
Triggers em nível de linha e tabela
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION