Alors, les amis, maintenant que vous avez déjà chopé les bases sur les triggers, leurs types, comment ça marche et même comment en créer pour différentes tâches, il est temps de parler d’un truc super important. Comme souvent en dev, savoir ce qu’on peut faire c’est cool, mais savoir ce qu’il ne faut surtout pas faire, c’est tout aussi crucial. Aujourd’hui, on va décortiquer les erreurs classiques que font les devs avec les triggers, histoire que vous puissiez les éviter et vous épargner quelques heures (ou jours !) de debug galère.
Récursion des triggers : le trigger s’appelle lui-même
C’est clairement l’erreur préférée des débutants. Imagine que tu crées un trigger qui met à jour une colonne, genre last_modified. Mais dès que cette modif a lieu, l’update déclenche à nouveau le trigger. Boucle infinie, et ton serveur finit par planter avec une erreur de stack overflow.
Exemple :
CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
-- On met à jour le champ 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();
Qu’est-ce qui cloche ici ? L’opération UPDATE dans la fonction déclenche le même trigger qui l’a créée. Et voilà, boucle infinie.
Comment éviter ça :
Utilise la variable OLD et compare les valeurs avant de faire la modif :
CREATE OR REPLACE FUNCTION update_last_modified_safe()
RETURNS TRIGGER AS $$
BEGIN
-- On vérifie si la valeur a changé
IF NEW.last_modified IS DISTINCT FROM OLD.last_modified THEN
NEW.last_modified = NOW();
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Assure-toi de ne pas lancer d’opérations inutiles dans le trigger.
Mauvaise utilisation de OLD et NEW
Ces variables sont tes meilleures potes quand tu bosses avec les triggers, mais mal utilisées, elles peuvent te filer de sacrés maux de tête. OLD contient les données avant la modif de la ligne, NEW celles qui seront sauvegardées après la modif.
L’erreur classique, c’est de mal interpréter ou d’essayer d’utiliser ces variables là où elles n’existent pas. Par exemple, dans un trigger BEFORE INSERT, OLD n’existe pas — la ligne vient juste d’être créée.
Exemple d’erreur :
-- Ça va planter, car OLD n’existe pas lors d’un 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;
Comment éviter ça :
Fais gaffe à bien choisir où utiliser OLD et NEW :
OLDdispo pour les opérationsUPDATEetDELETE.NEWdispo pour les opérationsINSERTetUPDATE.
Triggers multiples sur une même opération
Dans PostgreSQL, tu peux créer plusieurs triggers sur la même opération et la même table. Ça a l’air pratique, mais en vrai, ça peut vite devenir le bazar si les triggers se marchent dessus ou modifient les mêmes données.
Exemple :
-- Trigger 1
CREATE OR REPLACE FUNCTION trigger_one()
RETURNS TRIGGER AS $$
BEGIN
-- Logique du trigger 1
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger 2
CREATE OR REPLACE FUNCTION trigger_two()
RETURNS TRIGGER AS $$
BEGIN
-- Logique du trigger 2
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Création de deux 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();
Les deux triggers vont s’activer à chaque insert dans my_table. Si leur logique n’est pas bien synchronisée, ça peut donner des résultats imprévisibles.
Comment éviter ça :
- Planifie l’architecture de tes triggers à l’avance.
- Si les triggers touchent à la même logique, regroupe-les dans un seul trigger.
Problèmes de performance
Les triggers ajoutent du calcul à chaque opération liée. Si tu mets des triggers sur des tables très sollicitées ou volumineuses, ça peut plomber les perfs de ta base.
Mauvais exemple :
CREATE OR REPLACE FUNCTION heavy_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
-- Opération lourde exécutée à chaque update de ligne
PERFORM some_heavy_query();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER performance_killer AFTER UPDATE ON huge_table EXECUTE FUNCTION heavy_trigger_function();
Comment éviter ça :
- Réduis au max la logique dans le trigger. Si tu dois faire un truc lourd, pense à le déporter en tâche de fond.
- Utilise des conditions pour limiter l’exécution du trigger, avec
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 et transactions
Les triggers s’exécutent dans la transaction lancée par ta requête. Si une erreur survient dans le trigger, toute la transaction est rollback. Ça peut être utile parfois, mais ça peut aussi causer des surprises si tu n’as pas prévu la gestion d’erreur.
Exemple d’erreur :
CREATE OR REPLACE FUNCTION error_prone_trigger()
RETURNS TRIGGER AS $$
BEGIN
-- Erreur volontaire
RAISE EXCEPTION 'Quelque chose s’est mal passé !';
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Si ce trigger se déclenche, la transaction de ta requête principale sera annulée.
Comment éviter ça :
Ajoute de la gestion d’erreur dans tes triggers pour limiter l’impact sur la transaction principale :
CREATE OR REPLACE FUNCTION safe_trigger()
RETURNS TRIGGER AS $$
BEGIN
BEGIN
-- Code qui peut planter
INSERT INTO another_table VALUES (NEW.data);
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Une erreur est survenue, mais on l’a gérée proprement.';
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Conseils pratiques
Garde tes triggers aussi simples que possible. Si tu trouves qu’un trigger devient trop gros ou trop complexe, c’est sûrement qu’il faut le découper en plusieurs fonctions ou revoir la logique.
Teste toujours tes triggers sur peu de données. Avant de brancher un trigger sur une table critique, essaye-le sur des données de test.
Documente tes triggers. Dans quelques mois, toi ou tes collègues aurez peut-être oublié pourquoi tel trigger existe. Une doc claire t’évitera bien des prises de tête.
Évite les triggers pour des tâches faisables côté appli. Les triggers sont top pour automatiser des trucs à exécuter direct, mais pour de la logique métier complexe, ça peut vite devenir galère.
Surveille les perfs. Checke régulièrement l’impact de tes triggers sur la perf de la base, surtout si tes données ou la charge augmentent.
Avec ces conseils et ce que t’as appris aujourd’hui, t’es prêt non seulement à créer des triggers, mais à en écrire qui tournent bien, efficacement, et sans mauvaises surprises.
GO TO FULL VERSION