Vous n'êtes pas identifié(e).
Pages : 1
Bonjour à tous !
Je voulais savoir s'il est possible de faire une reqûete en mentionnant d'ignorer un trigger. Je m'explique :
J'ai une table avec plusieurs centaines de milliers d'enregistrements, ce sont des commentaires faits sur des objets (un commentaire = clé primaire).
create table commentaires (
id_commentaire integer primary key
id_objet integer,
commentaire text,
date_creation timestamp,
is_last boolean
J'ai besoin de savoir quel est le commentaire le plus récent de chaque objet. Lorsque je supprime un commentaire, je dois donc trouver le nouveau commentaire le plus récent sur le même objet.
J'ai fait un trigger "AFTER DELETE" qui va systématiquement chercher le nouveau commentaire le plus récent, que je marque en indiquant is_last = true.
-- extrait trigger :
if (TG_OP = 'DELETE') then
update commentaire
set is_last = true
where id_commentaire = public.Find_Last_Comment(OLD.id_object); -- cette fonction retourne l'id du dernier commentaire pour l'objet donné
return old;
end if;
Tout fonctionne très bien lorsque je supprime les commentaires un à un. En revanche, lorsque je supprime un objet, je supprime ensuite tous les commentaires qui lui sont attribués :
-- suppression d'un seul commentaire :
delete from commentaires
where id_commentaire = 12;
-- suppression d'un objet puis de tous ses commentaires :
delete from objets
where id_objet = 45660;
delete from commentaires
where id_objet = 45660;
Le problème est que je peux avoir plusieurs centaines de commentaires sur un même objet. Le trigger sur commentaires est donc fait autant de fois, alors que sa fonction n'a plus de sens vu que le but est de trouver le dernier commentaire d'un objet, objet qu'on vient de supprimer... j'ai essayé d'adapter le trigger pour qu'il en fasse le moins possible :
-- extrait trigger :
if (TG_OP = 'DELETE') then
if not exists (select true from objets where id_objet = OLD.id_objet) then
return null;
end if;
update commentaire
set is_last = true
where id_commentaire = Find_Last_Comment(OLD.id_object);
return old;
end if;
mais même comme cela, le test d’existence de l'objet est fait plusieurs centaines de fois et du coup la requête initiale "delete from commentaires where id_objet = 45660" est très très longue....
D'où ma question : est-il possible de passer une commande en lui indiquant d'ignorer un trigger :
-- suppression d'un seul commentaire, pas de chanagement:
delete from commentaires
where id_commentaire = 12
-- suppression d'un objet puis de tous ses commentaires en ignorant le trigger
delete from objets
where id_objet = 45660;
delete from commentaires
where id_objet = 45660
with trigger my_trigger not executed;
J'ai également pensé à mettre le trigger à disable, mais je n'ai pas trouvé comment le faire que pour la session active. Si quelqu'un d'autre au même moment supprime un commentaire, pour lui le trigger doit rester actif !
Et sinon, voyez-vous un autre moyen ?
Merci beaucoup !
Dernière modification par thomasp (12/02/2016 18:20:48)
Hors ligne
Bonsoir,
pour désactiver un trigger il n'y a pas à ma connaissance d'autres possibilités que d'utiliser ALTER TABLE ... DISABLE TRIGGER ...
De plus cette commande prend un verrou (SHARE ROW EXCLUSIVE) de telle manière qu'aucune autre session ne puisse modifier la table de manière concurrente ce qui peut être embêtant si il y a pas mal d'accès simultané.
Les solutions alternatives ? Quelques pistes:
- Le trigger pourrait être mis sur l'INSERT non ?
- Un trigger est-il nécessaire ? Pourquoi ne pas faire une requête ad-hoc lorsque vous avez besoin du dernier commentaire ? Problème de performance ? Ajout d'un index sur la table commentaires (CREATE INDEX ON commentaires(id_objet, date_creation)) ?
- Créer une table spécifique qui ne stocke qu'une référence sur le dernier commentaire de chaque objet (à mettre à jour par exemple via un/des trigger(s) sur la table principale commentaires):
CREATE TABLE last_commentaires(
id_objet integer
, id_last_commentaire integer
, PRIMARY KEY(id_objet, id_last_commentaire)
, FOREIGN KEY(id_objet) REFERENCES objets(id_objet)
ON DELETE CASCADE
, FOREIGN KEY(id_last_commentaire) REFERENCES commentaires(id_commentaire)
ON DELETE CASCADE
);
Éric
Hors ligne
mince c'est bien ce que je pensais...
oui en effet votre deuxième proposition est ce que j'ai sous la main si je ne trouve pas de solution via le trigger.
merci !
Hors ligne
Pages : 1