35.6. Règles contre déclencheurs
Beaucoup de choses pouvant se faire avec des déclencheurs 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 déclencheur.
D'un autre côté, un déclencheur qui est lancé sur un
insert
pour une vue peut faire la
même chose qu'une règle : placez les données ailleurs et supprimez
les insertions dans la vue. Mais, il ne pourra pas faire la même
chose avec un
update
ou
un
delete
parce qu'il
n'y a pas de vraies données sur la vue qui pourraient être
parcourues. Du coup, le déclencheur ne serait jamais appelé. Seule
une règle pourra vous aider.
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
déclencheur est exécuté une fois pour chaque ligne affectée. Une
règle manipule 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 déclencheur appelé pour chaque ligne et qui devra exécuter ces
opérations autant de fois. Néanmoins, l'approche du déclencheur 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
déclencheur 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 déclencheur devrait implémenter une contrainte qui supprime les
lignes de logiciel référençant un ordinateur
supprimé. Le déclencheur utiliserait cette commande :
DELETE FROM logiciel WHERE nom_hote = $1;
Comme le déclencheur 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 déclencheur 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
déclencheur 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 déclencheur 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 déclencheur 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
déclencheur 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 déclencheurs si leur actions résultent en des
jointures larges et mal qualifiées, une situation où le planificateur
échoue.