Si t'as déjà eu le cas où tu dois faire une action pour chaque ligne lors d'une mise à jour massive de données, ou alors juste une seule fois pour toute la table, tu t'es sûrement demandé : comment faire ça au mieux ? PostgreSQL propose deux options : les triggers au niveau des lignes et ceux au niveau des opérations. Comprendre quand utiliser chaque approche, c'est super important pour bien concevoir ta base de données, optimiser ses perfs et éviter les bugs. On va voir ça ensemble !
Les triggers qui bossent au niveau des lignes (FOR EACH ROW) se déclenchent à chaque fois pour chaque ligne touchée par une opération INSERT, UPDATE ou DELETE. Donc, si ta requête SQL touche 100 lignes, le trigger va tourner 100 fois.
Quand les utiliser ?
Les triggers au niveau des lignes sont utiles si tu dois traiter chaque ligne modifiée séparément. Par exemple :
- Logger les changements pour chaque ligne.
- Mettre à jour automatiquement des données liées pour chaque ligne.
Exemple : logger les changements pour chaque ligne
Imaginons qu'on a une table d'étudiants :
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
On veut logger chaque ligne qui est modifiée dans cette table, dans une table séparée students_log :
CREATE TABLE students_log (
log_id SERIAL PRIMARY KEY,
student_id INT,
old_name VARCHAR(100),
new_name VARCHAR(100),
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Fonction pour logger les changements :
CREATE OR REPLACE FUNCTION log_student_update()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO students_log(student_id, old_name, new_name, changed_at)
VALUES (OLD.id, OLD.name, NEW.name, CURRENT_TIMESTAMP);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Création du trigger FOR EACH ROW :
CREATE TRIGGER student_update_logger
AFTER UPDATE ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_update();
Test :
UPDATE students
SET name = 'Ivan Ivanov'
WHERE id = 1;
Après cette requête, tu verras une entrée dans la table students_log avec tous les détails du changement.
Triggers au niveau des opérations (FOR EACH STATEMENT)
Les triggers au niveau des opérations (FOR EACH STATEMENT) se déclenchent une seule fois pour toute la requête SQL, peu importe combien de lignes sont touchées. Si la requête met à jour 100 lignes, le trigger ne s'exécutera qu'une fois.
Les triggers au niveau des opérations sont utiles si tu veux :
- Faire une action une seule fois pour toute l'opération.
- Travailler avec des données agrégées ou faire des calculs pour toute la table.
Exemple : mise à jour d'un compteur de changements
Imaginons qu'on a une table de compteur de changements pour la table students :
CREATE TABLE students_changes_log (
total_changes INT DEFAULT 0
);
INSERT INTO students_changes_log(total_changes) VALUES (0);
On veut augmenter la valeur de ce compteur à chaque fois qu'une opération UPDATE est faite sur la table students.
Fonction pour mettre à jour le compteur :
CREATE OR REPLACE FUNCTION increment_changes_counter()
RETURNS TRIGGER AS $$
BEGIN
UPDATE students_changes_log
SET total_changes = total_changes + 1;
RETURN NULL; -- Un trigger au niveau des opérations ne retourne pas de lignes
END;
$$ LANGUAGE plpgsql;
Création du trigger FOR EACH STATEMENT :
CREATE TRIGGER update_changes_counter
AFTER UPDATE ON students
FOR EACH STATEMENT
EXECUTE FUNCTION increment_changes_counter();
Test :
UPDATE students
SET age = age + 1
WHERE age < 20;
Après cette requête, le trigger va se lancer une seule fois et le compteur de changements sera incrémenté de un.
Comparaison FOR EACH ROW et FOR EACH STATEMENT
| Critère | FOR EACH ROW | FOR EACH STATEMENT |
|---|---|---|
| Niveau d'exécution | Pour chaque ligne touchée | Une fois pour toute l'opération |
| Fréquence d'appel | Un appel par ligne | Un appel par requête SQL |
| Tâches | Logger les changements individuels, traitement des lignes | Agrégation, mise à jour de la méta-info |
| Exemple | Logger les changements pour chaque ligne | Mise à jour du compteur de changements |
| Performance | Plus coûteux pour les opérations massives | Moins coûteux pour les opérations massives |
Quand utiliser FOR EACH ROW et FOR EACH STATEMENT ?
Utilise FOR EACH ROW si :
- Tu veux que le trigger s'exécute pour chaque ligne.
- La logique doit être liée aux changements de lignes précises.
- Tu as besoin d'accéder aux données
OLDetNEWpour chaque ligne.
Exemple : Logger les changements dans une table ou créer automatiquement des entrées liées.
Utilise FOR EACH STATEMENT si :
- Tu veux faire une action une seule fois pour toute l'opération.
- La logique du trigger ne dépend pas des changements de lignes précises.
- La performance est critique et tu veux éviter de lancer le trigger plein de fois.
Exemple : Mise à jour de compteurs, calcul de méta-données pour la table.
Erreurs et points importants
Choisir le bon type de trigger, c'est pas toujours évident, alors voilà ce qu'il faut garder en tête :
- Une des erreurs les plus courantes, c'est d'essayer d'utiliser les données
OLDetNEWdans un triggerFOR EACH STATEMENT. Ça va planter, car ces variables ne sont dispos que dans les triggers au niveau des lignes. - Les triggers au niveau des lignes (
FOR EACH ROW) peuvent vraiment ralentir les opérations si la requête touche beaucoup de lignes. Pense toujours à la perf. - Fais gaffe à la récursivité potentielle des triggers. Par exemple, si un trigger modifie des données dans la même table, ça peut partir en boucle infinie.
GO TO FULL VERSION