Arjuna a écrit :
Un SGBD-R permet de gérer les relations entre les éléments, et de les "enforce", c'est à dire d'en assurer l'intégrité.
Ainsi, on note deux systèmes de verroux de base et un personnalisable.
Les verroux de base.
Il s'agit des clés primaires et étrangères.
Pour ce qui est de la clé primaire, lorsqu'un champ (ou un tuple de champs) est spécifié comme clé primaire, alors le moteur de la base de données va interdire que ce tuple prennent plusieurs fois la même valeur.
Et niveau clé étrangère, cette fois le SGBD va s'assurer avant l'insertion de valeur dans ce tuple, que ces valeurs existent déjà dans la table de référence.
Ces deux systèmes de base permettent de s'assurer par exemple que deux clients n'auront pas le même numéro de client, ou qu'on ne pourra pas associer un produit qui n'existe pas à une commande.
Les verroux personnalisables.
Il s'agit des triggers. Plus que des verroux, un trigger permet de faire à peut près n'importe quelle action sur une action spécifique, sur un objet spécifique. Ainsi, on pourra par exemple se servir d'un trigger pour mettre à jour le prix total d'une commande lorsque la quantité d'un produit change. Etant des calculs évolués, cela permet au SGBD de se comporter exactement comme vous l'entendez.
Ces méthodes permettent de mettre en application les méthodes d'analyse tels que Merise, et d'assurer, au sein du stockage des données, l'intégralité et la cohérence de ces dernières.
Sur le papier, tout ça c'est très bien... Mais... Oui, il y a un mais...
Regardons ce qu'il se passe sur une clé primaire.
-> Lorsqu'on ajoute une valeur, le SGBD va en premier rechercher la présence de cette valeur dans la table, puis l'insérer si elle n'existe pas. PUIS, étant donné qu'une clé primaire est systématiquement associée à un index unique, elle va vérifier l'existance de cet élément dans l'index unique, et l'ajouter si elle n'existe pas (ce qui est forcément le cas si on est allé jusque là).
Ca fait pas mal de trucs... Voyons voir ce que ça donne si on supprime cette contrainte, et qu'on ne garde que l'index unique.
-> Recherche de la valeur dans l'index. Si elle n'existe pas, insertion de la donnée, mise à jour de l'index, sinon, erreur.
On a fait 2 traîtements de moins.
=> Il ne faut pas utiliser de clé primaire sur une table. Un index unique suffit, et offre le même résultat en un temps plus rapide.
Deplus, les clé alternatives n'existant que rarement dans les SGBD, elles sont habituellement traîtées de cette façon, alors qu'il n'y a pas de raison de les différencier.
Maintenant, penchons-nous sur la clé étrangère.
-> Lorsque j'insère une donnée dans la table "fille", je regarde si la donnée liée existe dans la table mère. Si elle existe, j'insère ma ligne, et si elle n'existe pas, je fait une erreur. Ceci peut prendre pas mal de temps si la table mère contient beaucoup de données, ou que le tuple servant de lien est gros.
Lorsque je supprime une donnée de la table "mère", je regarde si des données de la table fille y font référence. Si oui, alors je plante, sinon je supprime la ligne. Ceci est encore plus lent, puisque très généralement il y a plus de filles que de mères. Sans compter le fait que du côté mère, ce champ est forcément unique, tandis que côté fille, il ne l'est pas.
Quand j'ai un programme qui me permet de remplir un formulaire ou les données de la table mère sont listées dans une dropdown list, quel est l'intérêt d'aller vérifier qu'elle existent dans la table mère au moment de l'insertion ? Aucun, puisque ces données existes forcément !
Et dans un traîtement de suppression d'une donnée de référence, pour éviter de planter si des données existent dans la table fille, on va de toute façon nettoyer cette dernière en premier. Ainsi, au moment du delete sur la table mère, on est certains qu'il ne peut pas y avoir de filles, vu qu'on vient de toutes les effacer. A nouveau, aucun intérêt.
=> Les clé étrangères ne servent donc à rien, et c'est au programme de s'assurer de l'intégrité des données lors de ces accès à la base. Il vaut donc mieu éviter de les utiliser, afin d'économiser les traîtements inutiles.
A noter deplus le problème du CASCADE CONSTRAINTS. Cette fabuleuse commande permet de supprimer une mère et toutes ses filles en une ligne.
Elle a aussi la formidable capacité à vider la moitiée des tables de la base en une seconde si on écrit mal la requête... Dans ce cas, le segment de rollback étant sous-dimensionné, ça plante, et on ne peut plus faire rollback. La catastrophe. Sans clé étrangère, aucun risque, le CASCADE CONSTRAINTS ne retrouvant pas de cheminement entre les table, ne pourra faire aucun dégat.
-> Les triggers. Un trigger s'éxécute sur différents évèments et différentes actions sur différents objets. Un trigger est généralement utilisé sur une table (mais ça peut aussi bien être sur une vue pour les SGBD récents), avant ou après la modification de la table, sur une insertion, une suppression ou/et une mise à jour.
L'éxécution du trigger sera systématique lorsqu'un tel traîtement aura lieu sur son l'objet qu'il surveille. Ainsi, si un trigger s'occupe de mettre à jour le montant d'une commande en fonction des produits qui y sont rattachés, la moindre modification d'un libellé d'un produit dans la liste va déclencher le calcul, même si aucune quantité ni prix n'a été modifié.
-> Un trigger fonctionne dans sa propre sous-transaction
-> Un trigger peut tout à fait déclencher d'autres triggers
-> A savoir qu'une sous-transaction fonctionne comme de la récusrivité : c'est la transaction principale qui encaisse tout. On voit rapidement que pour certains trigger un rollback segment fault risque d'arriver, avec toutes les erreurs et incohérences que cela peut engendrer.
-> Un trigger, étant écrit à la main, ne peut pas bénéficier des optimisation des PK et FK (qui sont en réalité des triggers automatiques), et se contenteront d'utiliser du code SQL et dérivés (PL/SQL ou T-SQL pour ne citer qu'eux), ce qui risque rapidement de prendre du temps.
=> La plus part des traîtements par trigger peuvent être évités en faisant attention à ce qu'on fait au niveau du programme qui utilise la base de données. Le calcul d'un total d'une commande notamment, n'a rien à faire dans la base, il a sa place dans le programme, d'autant plus que c'est plus évident de modifier un programme pour y rajouter des frais de port ou la TVA que dans un trigger...
En bref, les triggers sont à éviter autant que possible. Les seuls qui sont vraiment acceptables, sont ceux qui vont s'occuper de générer un identifiant (pour les bases qui n'ont pas de fonction native).
On crééra alors un trigger "on before insert" qui s'occupera d'aller récupérer la valeur d'une séquence par exemple. Sorti de ça, les tests comme exclusion de champs, surtout lorsque le trigger se lève sur un traîtement fréquent, et lorsque ses traîtements sont longs, doivent impérativement déportés dans l'application.
Voilà. C'était juste parceque j'avais rien à faire et que j'ai pas de question à poser, et y'a pas de réponse auxquelles répondre, donc j'étalle ma science, ça peu toujours servir si un jour une personne se pose la question
|