Beaucoup de choses pouvant se faire avec des triggers peuvent aussi
être implémentées en utilisant le système de règles de
PostgreSQL. un des points qui ne pourra pas être
implémenté par les règles en certains types de contraintes, notamment les
clés étrangères. Il est possible de placer une règle qualifiée qui réécrit
une commande en nothing
si la valeur d'une colonne n'apparaît
pas dans l'autre table. Mais alors les données sont jetées et ce n'est pas
une bonne idée. Si des vérifications de valeurs valides sont requises et
dans le cas où il y a une erreur invalide, un message d'erreur devrait être
généré et cela devra se faire avec un trigger.
Dans ce chapitre, nous avons ciblé l'utilisation des règles pour mettre à
jour des vues. Tous les exemples de règles de mise à jour de ce chapitre
peuvent aussi être implémentés en utilisant les triggers
INSTEAD OF
sur les vues. Écrire ce type de triggers
est souvent plus facile qu'écrire des règles, tout particulièrement si
une logique complexe est requise pour réaliser la mise à jour.
Pour les éléments qui peuvent être implémentés par les deux, ce qui sera le mieux dépend de l'utilisation de la base de données. Un trigger est exécuté une fois pour chaque ligne affectée. Une règle modifie la requête ou en génère une autre. Donc, si un grand nombre de lignes sont affectées pour une instruction, une règle lançant une commande supplémentaire sera certainement plus rapide qu'un trigger appelé pour chaque ligne et qui devra exécuter ces opérations autant de fois. Néanmoins, l'approche du trigger est conceptuellement plus simple que l'approche de la règle et est plus facile à utiliser pour les novices.
Ici, nous montrons un exemple où le choix d'une règle ou d'un trigger joue sur une situation. Voici les deux tables :
CREATE TABLE ordinateur ( nom_hote text, -- indexé constructeur text -- indexé ); CREATE TABLE logiciel ( logiciel text, -- indexé nom_hote text -- indexé );
Les deux tables ont plusieurs milliers de lignes et les index sur
nom_hote
sont uniques. La règle ou le trigger devrait
implémenter une contrainte qui supprime les lignes de logiciel
référençant un ordinateur supprimé. Le trigger utiliserait cette
commande :
DELETE FROM logiciel WHERE nom_hote = $1;
Comme le trigger est appelé pour chaque ligne individuelle supprimée à
partir de ordinateur
, il peut préparer et sauvegarder le plan pour
cette commande et passer la valeur nom_hote
dans le paramètre.
La règle devra être réécrite ainsi :
CREATE RULE ordinateur_del AS ON DELETE TO ordinateur DO DELETE FROM logiciel WHERE nom_hote = OLD.nom_hote;
Maintenant, nous apercevons différents types de suppressions. Dans le cas d'un :
DELETE FROM ordinateur WHERE nom_hote = 'mypc.local.net';
la table ordinateur
est parcourue par l'index (rapide), et la
commande lancée par le trigger pourrait aussi utiliser un parcours
d'index (aussi rapide). La commande supplémentaire provenant de la règle
serait :
DELETE FROM logiciel WHERE ordinateur.nom_hote = 'mypc.local.net' AND logiciel.nom_hote = ordinateur.nom_hote;
Comme il y a une configuration appropriée des index, le planificateur créera un plan :
Nestloop -> Index Scan using comp_hostidx on ordinateur -> Index Scan using soft_hostidx on logiciel
Donc, il n'y aurait pas trop de différence de performance entre le trigger et l'implémentation de la règle.
Avec la prochaine suppression, nous voulons nous débarrasser des 2000
ordinateurs où nom_hote
commence avec old
. il
existe deux commandes possibles pour ce faire. Voici l'une d'elle :
DELETE FROM ordinateur WHERE nom_hote >= 'old' AND nom_hote < 'ole'
La commande ajoutée par la règle sera :
DELETE FROM logiciel WHERE ordinateur.nom_hote >= 'old' AND ordinateur.nom_hote < 'ole' AND logiciel.nom_hote = ordinateur.nom_hote;
avec le plan :
Hash Join -> Seq Scan on logiciel -> Hash -> Index Scan using comp_hostidx on ordinateur
L'autre commande possible est :
DELETE FROM ordinateur WHERE nom_hote ~ '^old';
ce qui finira dans le plan d'exécution suivant pour la commande ajoutée par la règle :
Nestloop -> Index Scan using comp_hostidx on ordinateur -> Index Scan using soft_hostidx on logiciel
Ceci monte que le planificateur ne réalise pas que la qualification pour
nom_hote
dans ordinateur
pourrait aussi être
utilisée pour un parcours d'index sur logiciel
quand il existe
plusieurs expressions de qualifications combinées avec and
, ce
qui correspond à ce qu'il fait dans la version expression rationnelle de la
commande. Le trigger sera appelé une fois pour chacun des 2000 anciens
ordinateurs qui doivent être supprimées, et ceci résultera en un parcours
d'index sur ordinateur
et 2000 parcours d'index sur
logiciel
. l'implémentation de la règle le fera en deux commandes
qui utilisent les index. Et cela dépend de la taille globale de la table
logiciel
, si la règle sera toujours aussi rapide dans la
situation du parcours séquentiel. 2000 exécutions de commandes à partir du
trigger sur le gestionnaire SPI prend un peu de temps, même si tous les
blocs d'index seront rapidement dans le cache.
La dernière commande que nous regardons est :
DELETE FROM ordinateur WHERE constructeur = 'bim';
De nouveau, ceci pourrait résulter en de nombreuses lignes à supprimer dans
ordinateur
. donc, le trigger lancera de nouveau de nombreuses
commandes via l'exécuteur. La commande générée par la règle sera :
DELETE FROM logiciel WHERE ordinateur.constructeur = 'bim' AND logiciel.nom_hote = ordinateur.nom_hote;
Le plan pour cette commande sera encore la boucle imbriquée sur les deux
parcours d'index, en utilisant seulement un index différent sur
ordinateur
:
Nestloop -> Index Scan using comp_manufidx on ordinateur -> Index Scan using soft_hostidx on logiciel
Dans chacun de ces cas, les commandes supplémentaires provenant du système de règles seront plus ou moins indépendantes du nombre de lignes affectées en une commande.
Voici le résumé, les règles seront seulement significativement plus lentes que les triggers si leur actions résultent en des jointures larges et mal qualifiées, une situation où le planificateur échoue.