Contraintes d'intégrité dans une base de données relationnelle - faut-il les ignorer?

10

Je suis en discussion permanente avec les développeurs de l'entreprise où je travaille car ils disent qu'il vaut mieux se débarrasser de l'application des relations (via les définitions de contraintes FOREIGN KEY) dans une base de données relationnelle afin d'accélérer les grosses requêtes et de gagner en efficacité performance.

La plate-forme à l'étude est MySQL 5.x, et aucune clé étrangère n'a été configurée, même certaines contraintes PRIMARY KEY des tables concernées manquent, ce qui, au moins pour moi, n'est pas raisonnable. Ils ont peut-être raison et je me trompe, mais je n'ai pas assez d'arguments pour discuter de cette situation.

C'est l'approche privilégiée depuis maintenant trois ans. Je suis nouveau dans cette entreprise (seulement un mois) mais, comme le produit «fonctionne», il y a une hésitation à améliorer la base de données; nevertheles, la première chose que j'ai remarquée est qu'une page prend 1 minute à charger (oui, 60 secondes!).

L'une des affirmations derrière la situation actuelle est qu'une base de données «dénormalisée» est plus rapide qu'une base de données normalisée, mais je ne pense pas que ce soit vrai.

La plupart des requêtes pertinentes incluent des opérations JOIN, ce qui les rend très, très, très lentes avec de grandes quantités de données (la base de données contient des millions de lignes).

Généralement, la gestion des opérations «CRUD» est implémentée au niveau du code du programme d'application; par exemple, pour SUPPRIMER certaines données de, disons TableA:

  • il faut d'abord vérifier à la volée s'il existe une relation entre les rangées de TableAet TableB,
  • dans le cas où cette relation est "détectée", le code du programme d'application ne permettra pas de SUPPRIMER la ou les lignes pertinentes, mais
  • si, pour une raison quelconque, le code du programme d'application échoue, l'opération DELETE «réussira», peu importe s'il existe une relation concernant les lignes et les tables impliquées.

Question

Pourriez-vous m'aider à élaborer une bonne réponse, précise et solide, pour enrichir le débat?


Remarque : Peut-être que quelque chose comme ça a été demandé (et répondu) avant, mais je n'ai rien trouvé via Google.

ReynierPM
la source
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White 9

Réponses:

12

Si, comme indiqué dans votre message, l'intention est de créer une base de données relationnelle (RDB pour plus de concision) et, par conséquent, il est prévu qu'elle fonctionne en tant que telle, la réponse courte est:

  • Non, vous ne devez pas ignorer les contraintes d'intégrité des données .

L'objectif principal devrait être de gérer les données pertinentes telles quelles, un atout organisationnel très précieux, et une manière fiable d'atteindre cet objectif est d'employer des moyens techniques qui s'appuient sur une théorie solide.

Ainsi, en tant que professionnels de la base de données, vous pouvez profiter des mécanismes de modèle relationnel de pointe et élégants fournis par le Dr EF Codd pour appliquer les règles commerciales et éviter les problèmes qui pourraient éventuellement survenir s'ils ne sont pas utilisés.

À cet égard, je partagerai (a) ma vision globale des contraintes ainsi que (b) plusieurs considérations sur l'état de la base de données et l'environnement de travail en cause comme suit.

Contraintes de FOREIGN KEY, relations de données et intégrité référentielle

Un RDB doit refléter les caractéristiques du contexte commercial d'intérêt avec une grande précision, ce qui nécessite certainement une analyse conceptuelle approfondie menée par un modélisateur ou un concepteur qui suit les meilleures pratiques, en comptant avec l'aide indispensable des experts en affaires. Cette analyse doit permettre d'identifier et de formuler correctement les règles commerciales applicables .

Par conséquent, si un tel modélisateur a identifié qu'il existe des interrelations entre les données pertinentes, il doit configurer les restrictions de niveau logique correspondantes afin que le système de gestion de base de données (SGBD) puisse garantir que les données restent cohérentes avec les caractéristiques exactes et règles déterminées dans l'analyse mentionnés ci - dessus en tout temps .

En ce qui concerne la base de données en discussion, on peut déduire que les interrelations pertinentes ont été identifiées, puisque vous mentionnez qu'il y a une tentative procédurale (et facile à contourner) de les faire appliquer de l'extérieur des installations du SGBD, à force de code de programme d'application (qui est une approche pré-relationnelle) qui dans tous les cas doit «toucher» la base de données pour tenter de valider l'intégralité desdites interrelations.

Cependant, comme vous le savez, ce n'est pas la technique optimale pour protéger l' intégrité référentielle , car la science relationnelle a prescrit un instrument très puissant à cet effet, à savoir les contraintes FOREIGN KEY (FK). Ces contraintes sont très faciles à créer (via l'approche déclarative supérieure) car ce sont des phrases uniques qui évitent de recourir à des procédures ad hoc inutiles et sujettes aux erreurs. Il est très utile de noter que la vitesse d'exécution des contraintes FK a été hautement optimisée par des programmeurs spécialisés (et les principaux fournisseurs de plates-formes y travaillent depuis des décennies maintenant).

De plus, puisqu'un RDB doit être un composant logiciel indépendant (autoprotecteur, auto-descriptif, etc.) pouvant être accédé par plusieurs programmes d'application (bureau, automatique, web, mobile, combinaisons de ceux-ci), il ne doit pas être «Couplé» avec le code de l'une de ces applications.

De même, les données - étant une ressource organisationnelle importante - ont naturellement tendance à survivre aux programmes d'application, aux programmeurs d'application, aux plates-formes de développement d'applications et aux paradigmes de programmation.

Contraintes de CLÉ PRIMAIRE et implications des lignes en double

Lorsque, d'un point de vue conceptuel, un type particulier de chose a été jugé important dans un environnement commercial, un modélisateur de base de données doit (1) déterminer ses caractéristiques pertinentes - c'est-à-dire ses propriétés -, confirmer ce genre de chose en tant que prototype d' instances d'entité - c'est-à-dire un type d'entité - et (2) le représentent au moyen d'un tableau qui est intégré par une ou plusieurs colonnes dans une conception logique.

Ensuite, tout comme il est primordial de distinguer chaque instance individuelle d'un type d'entité donné dans le monde réel, chaque ligne incluse dans une table doit également être distinguée de manière unique. Si une table n'a pas de clé déclarée, elle conservera éventuellement des doublons, et s'il y a deux lignes ou plus qui conservent exactement les mêmes valeurs, alors elles ont toutes la même signification , elles représentent toutes le même fait .

Sur ce point, les lignes en double doivent être supprimées pour plusieurs raisons. D'un point de vue théorique, le concepteur doit s'assurer que chaque ligne est toujours unique dans le but d'avoir des tables qui fonctionnent aussi bien que le permet le sous-langage de données SQL (ayant des répercussions importantes sur les opérations de manipulation de données). En outre, d'un point de vue informationnel, si plusieurs lignes représentent le même fait, leur enregistrement est non seulement superflu mais nuisible , comme illustré ci-dessous:

  • Supposons que quelqu'un ait inséré deux lignes identiques dans une certaine table.
  • Plus tard, quelqu'un d'autre vient et met à jour une seule occurrence des doublons. Par conséquent, l'autre occurrence n'est plus à jour.
  • Successivement, une autre personne met à jour l'occurrence qui n'avait pas été modifiée jusqu'à présent. De cette manière, les deux doublons ont subi des changements différents à des moments différents dans le temps.
  • Après cela, lorsque quelqu'un souhaite sélectionner les informations véhiculées par les lignes en question, il peut en trouver deux «versions» différentes.

De cette façon:

  • Quelle «version» peut être considérée comme correcte et fiable?
  • Lequel reflète fidèlement le monde réel?

Comme vous le savez, ce phénomène peut même avoir des implications juridiques, une circonstance qui a sûrement une énorme importance.

En outre, le temps et les efforts nécessaires pour gérer ces contradictions (peut-être par le biais d'une sorte de «synchronisation de mise à jour») devraient être mieux consacrés aux tâches qui produisent réellement de la valeur pour votre organisation. Ainsi, la conservation de lignes contradictoires doit être évitée par la conception pour conserver la cohérence d'une base de données intacte.

C'est pourquoi l'identification d'une CLÉ PRIMAIRE (PK) et la déclaration de la contrainte respective doivent toujours être effectuées par le concepteur de la base de données. Mais il faut aussi mentionner qu'une table peut avoir plus d'une colonne ou combinaison de colonnes qui contiennent des valeurs qui identifient de manière unique chaque ligne; en conséquence, outre la mise en place d'une contrainte PK (idéalement établie comme PRIMAIRE pour des raisons pragmatiques), le concepteur doit également déclarer une ou plusieurs CLES ALTERNATIVES (généralement définies via une ou plusieurs contraintes UNIQUE plus NON NULES) le cas échéant (ce qui est assez commun).

Une autre propriété avantageuse des PK est que, lorsqu'ils sont «migrés» vers d'autres tables pour participer à des FK simples ou composites, ils peuvent aider à appliquer les ratios de cardinalité des relations qui existent entre les données. Tout cela, oui, au moyen de paramètres déclaratifs simples et efficaces, assurés par le SGBD.

(Actuel) Contraintes CHECK et validation sur une seule ligne

N'oublions pas la pertinence des contraintes (actuelles) CHECK qui, limitant de manière déclarative l'ensemble valide des valeurs de colonne d'une ligne (qui peut paraître simple, mais qui est en fait une caractéristique fondamentale d'un SGBD relationnel), aident également à faire certains que les règles du contexte commercial sont reflétées avec précision à tout moment.

Comme vous avez marqué votre question avec la balise MySQL, il faut mentionner que, malheureusement, une telle plate-forme permet la déclaration de ce type de contrainte mais, en même temps, ignore son application! , situation qui, naturellement, a été signalée comme un bug depuis 2004 .

À cet égard, vous devez prendre en charge ce facteur par d'autres moyens, par exemple, les TRANSACTIONS ACIDES, les DÉCLENCHEURS ou d'autres méthodes dans le SGBD lui-même (voir cette réponse de @ ypercubeᵀᴹ pour des informations à ce sujet) afin que les données continuent à être cohérent.

Contraintes ASSERTION: configuration déclarative de règles métier multi-lignes et multi-tables supplémentaires

Un aspect qui, pour quelque raison que ce soit, est très mal pris en charge - voire pas du tout - par les différents SGBD SQL, y compris MySQL, permet les contraintes à plusieurs lignes et à plusieurs tables de manière déclarative - au-delà des PK et des FK, évidemment -.

Pour sa part, le standard SQL inclut des ASSERTIONS depuis de nombreuses années maintenant. Je ne sais pas quelles règles de votre environnement commercial bénéficieraient de cette approche de validation au niveau logique mais, en tant que concepteur de base de données, je considère qu'il serait assez pratique de contraindre les données avec une ou plusieurs ASSERTIONS, bien que je doive le mentionner à partir du Du point de vue des développeurs de SGBD, ce type d'outil primordial a été difficile à mettre en œuvre au niveau physique de l'abstraction.

Il semble que le vendeur Oracle et / ou les développeurs évaluent le soutien de AFFIRMATION depuis 2016, et qui amélioreraient que SGBD plus conforme et relationnellement, par conséquent, plus robuste et compétitif. Je suppose que, si (i) leurs consommateurs continuent de pousser et (ii) Oracle réussit dans la mise en œuvre, (iii) d'autres fournisseurs / communautés de SGBD devront également les activer, et leur utilisation commencera à se répandre. Ce serait certainement un énorme progrès dans le domaine de la gestion de bases de données, et étant l'un des outils les plus distinctifs envisagés par le Dr Codd, j'espère personnellement que nous verrons cela se produire bientôt.

Cohérence des données et processus décisionnel

Comme discuté ci-dessus, l'un des aspects les plus importants d'un RDB est qu'il garantit par lui-même la cohérence des données qu'il conserve, et cette cohérence n'est atteinte que lorsque le RDB est conforme aux contraintes d'intégrité déclarées par le modélisateur.

À cet égard, il est obligatoire d'avoir des tables de base (celles établies dans une structure DDL) dont l'intégrité est protégée afin de pouvoir créer des tables dérivées (par exemple, une instruction SELECT ou une vue qui récupère des colonnes de plusieurs tables) qui sont fiables. , car les tableaux dérivés doivent être nécessairement produits en termes de tableaux de base.

Il est bien connu que les gens utilisent l'information comme principal outil dans le processus décisionnel organisationnel (et ordinaire). Ensuite, si les informations présentées par une base de données ne sont pas cohérentes et précises, les décisions basées sur ces informations ne seront pas judicieuses (c'est le moins que l'on puisse dire). C'est pourquoi un RDB doit être soigneusement conçu et mis en œuvre: il doit être construit pour devenir une ressource fiable qui peut aider ses utilisateurs à prendre des décisions fondées.

«Dénormalisation»

Hélas, «une base de données« dénormalisée »est plus rapide qu'une base de données normalisée» est une idée fausse très répandue, bien qu'il s'agisse également d'un argument qui peut être réfuté pour des motifs logiques, physiques et pragmatiques.

Premièrement, la dénormalisation implique nécessairement qu'une table de base a été préalablement normalisée (en vertu d'une procédure formelle , basée sur la science, accomplie au niveau logique d'abstraction d'une base de données).

Donc, en supposant que ledit tableau était en fait normalisé correctement, en le «dénormalisant» (ce qui, contrairement au sens formel du mot, implique de lui ajouter des colonnes qui appartiennent à d'autres tableaux d'une annonce et en font également partie). mode spécial ) pourrait, par exemple, accélérer (au niveau physique) le traitement d'une seule ou de quelques instructions SELECT particulières, alors qu'une telle ligne de conduite pourrait, en même temps, compromettre l'exécution de nombreuses autres données associées opérations de manipulation (par exemple, plusieurs instructions INSERT, UPDATE, DELETE et SELECT, ou des combinaisons d'entre elles enfermées dans une ou plusieurs ACID TRANSACTIONS).

De plus, la dénormalisation (qu'elle soit formelle ou informelle) introduirait des anomalies de mise à jour / modification qui détérioreraient la cohérence de la base de données, un problème qui «peut» être traité par des procédures complexes, coûteuses et sujettes aux erreurs, lorsque tout cela peut être évité. au tout début.

Échafaudages au niveau physique prenant en charge les tableaux normalisés et «dénormalisés»

Une disposition logique (abstraite) (conception SQL-DDL) destinée à être utilisée dans le monde réel a clairement des répercussions physiques (concrètes) qui doivent être prises en compte.

De cette manière, une table «dénormalisée» serait nécessairement «plus large» (contenant des colonnes supplémentaires), ce qui signifie que ses lignes seraient nécessairement plus lourdes (nécessitant des composants de plus en plus importants au niveau physique), ce qui signifie que les processus informatiques sous-jacents (par exemple , ceux qui ont à voir avec le disque dur ou la mémoire) peuvent facilement ralentir.

En revanche, un tableau normalisé qui est bien sûr «plus étroit» (ayant moins de colonnes) serait un élément «plus léger» (desservi par des composants physiques de moins en moins nombreux) qui «se comporte plus rapidement», ce qui accélérerait la série d'actions liées à , par exemple, écriture et lecture de données.

Cela étant, il est très pratique de (a) normaliser les tables pertinentes de manière formelle et prudente, en les conservant en tant que telles, puis (b) d'utiliser toute ressource de niveau physique pouvant optimiser la vitesse de récupération et de modification des données, par exemple, la mise en œuvre une stratégie d'indexation minutieuse et efficace, permettant des configurations logicielles et matérielles de serveur appropriées, améliorant les capacités de bande passante du réseau, etc.

Le fonctionnement de la base de données à l'étude

Les paragraphes suivants de votre question portent sur la vitesse des opérations de récupération des données:

[Comme] le produit «fonctionne», il existe une hésitation à améliorer la base de données; néanmoins, la première chose que j'ai remarquée est qu'une page prend 1 minute à charger (oui, 60 secondes!).

Si le chargement d'une certaine page prend autant, il est évident que les utilisateurs du système ne reçoivent pas un bon service; par conséquent, même quand il "fonctionne", son fonctionnement ne semble pas du tout optimal, point qui démontre que vos intentions de rendre l'ensemble de l'environnement (base de données et applications) plus efficace sont bien soutenus et montre une attitude très constructive.

Ensuite, même lorsque la science vous soutient définitivement et que vous devez donc maintenir une posture ferme, je suggère d'aborder la situation de manière diplomatique, car à la fin de la journée, vos employeurs, vos collègues et vous unissez vos efforts pour faire de toute l'organisation plus de succès. Ainsi, c'est un argument sur lequel vous devez insister: pendant qu'ils font plus que bien d'autres choses, l'amélioration des pratiques générales et spécifiques de gestion des données peut considérablement aider à produire une croissance plus organisationnelle et individuelle.

La plupart des requêtes pertinentes incluent des opérations JOIN, ce qui les rend très, très, très lentes avec de grandes quantités de données (la base de données contient des millions de lignes).

Il convient de noter que l'opérateur JOIN est un élément essentiel et puissant qui se rapporte à la manipulation relationnelle des données. Ensuite, bien que des plates-formes plus robustes le servent avec des exécutions relativement plus rapides, la circonstance que vous décrivez est probablement un symptôme d'une conception non efficace (aux niveaux conceptuel, logique et physique de l'abstraction). Donc, mes premières estimations sont:

  • Les paramètres INDEX peuvent nécessiter des améliorations.
  • Les définitions de type et de taille des colonnes PK et FK doivent être revues (et je suis totalement d'accord avec @Rick James concernant ses considérations PK , car les clés composites ont tendance à être beaucoup plus efficaces que les substituts joints dans les cas appropriés).
  • Une normalisation plus poussée (formelle et fondée sur la science) pourrait aider à atténuer ces problèmes, du fait que, dans les bonnes circonstances (c'est-à-dire dans un RDB bien conçu), les JOIN sont exécutés très rapidement .

De plus, oui, comme @TommCatt le mentionne dans sa réponse , parfois une réécriture (logique) d'une requête modifie son plan d'exécution (physique) accélérant la lecture / écriture des données, ce qui est décidément un facteur à prendre en compte.

MDCCL
la source
1
Très bonne réponse. Lorsque je considère les performances d'une implémentation, je me rappelle toujours qu'une équipe de développeurs beaucoup plus intelligente que moi travaille sur ces problèmes depuis très longtemps. Les bases de données relationnelles sont au cœur des systèmes les plus énormes du monde (Facebook et Twitter pour n'en nommer que quelques-uns évidents).
Nick Bedford
9

La prémisse de base de vos développeurs est absolument fausse. Les clés étrangères auront un léger impact sur les performances du DML de votre système. Ils ne sont pas du tout utilisés dans les requêtes et n'ont donc aucun effet sur leurs performances. Vos développeurs ne savent donc pas de quoi ils parlent et sont les toutes dernières personnes à qui vous devriez envisager de demander conseil.

Les clés étrangères jouent un rôle essentiel dans le maintien de l'intégrité de vos données. Ceci est beaucoup plus important que toute petite amélioration des performances obtenue en les supprimant (même si c'était vrai).

Ne supprimez en aucun cas les FK d'une base de données OLTP.

De plus, la dénormalisation accélère parfois certaines requêtes. Cela, comme on dit, dépend. Pourtant, même s'il y a une certaine amélioration de la vitesse, cela ne vaut généralement pas l'effort supplémentaire pour maintenir l'intégrité des données.

Il est très rare qu'un simple réglage ne vous permette pas d'améliorer beaucoup plus la vitesse que la dénormalisation. C'est là qu'un bon DBA peut (enfin) gagner son salaire. Vous pouvez également régler vos requêtes. J'ai pris une fois une requête qui a retourné une réponse en pas moins de 30 minutes et je l'ai fait fonctionner en moins de 8 secondes. Aucune modification de la base de données, il suffit de réécrire la requête. Certes, c'est mon record personnel, donc votre kilométrage peut varier, mais la dénormalisation devrait être la dernière chose que vous essayez.

Vous souhaiterez peut-être également empêcher les requêtes plus compliquées d'être écrites par les développeurs. Demandez-leur quelles données ils veulent et dans quel format ils les veulent. Ensuite, donnez-leur des vues pour les leur donner. Les requêtes compliquées seront les vues. Il suffit alors aux développeurs d'écrire:

select <something> from <SomeView> where <whatever>;

Je suppose également que votre base de données est par ailleurs bien conçue. Une mauvaise conception de la base de données, voire de petites parties de celle-ci, peut vraiment ralentir les choses. J'ai souvent travaillé avec de très grandes tables (des milliards d'enregistrements chacune) avec des requêtes qui les joignaient à gauche et à droite et qui attendaient (et obtenaient) des réponses en quelques fractions de seconde. La taille d'une table n'est pas déterminante pour la vitesse de la requête.

Je grimace vraiment quand quelqu'un dit: "parce que le produit" fonctionne ", il y a une hésitation à améliorer la base de données." Si cette "hésitation" ressemble plus à "pas sur ma montre, mon pote!" vous voudrez peut-être même commencer à mettre à jour votre CV. Rien de bon ne vient jamais d'un tel environnement et vous serez blâmé pour chaque échec futur, même si vous avez fait du lobbying pendant des heures pour apporter un changement qui aurait empêché l'échec. Vous entendrez: «Ce n'est pas le bon moment pour faire des changements» encore et encore. Droite. Bonne chance.

TommCatt
la source
Une chose à noter est parfois que vous avez besoin de différentes requêtes pour les mêmes données en fonction de la quantité de données à renvoyer. Par exemple, une requête qui renvoie une seule ligne (ou même juste un nombre) peut être mieux écrite différemment qu'une requête renvoyant des milliers d'enregistrements.
Joe W
2

Changer le titre change la question. FOREIGN KEYssont facultatifs. Ils font:

  • Un FK crée implicitement un INDEXdans l'une des tables. Un tel index peut être ajouté manuellement. (Donc FK n'est pas nécessaire pour cela.)
  • Un FK vérifie l'intégrité. Il s'agit de la principale revendication de gloire du FK. Un FK n'est pas requis car votre application peut effectuer des vérifications similaires ou décider qu'une vérification n'est pas nécessaire. Donc...
  • Le contrôle d'intégrité coûte quelque chose en termes de performances; il ralentit donc le traitement. (Ce n'est généralement pas un gros problème.)
  • Les FK ne font pas tout ce que tout le monde veut; ce forum est jonché de questions «pourquoi les FK ne peuvent-ils pas faire X». En particulier, l' CHECKoption n'est pas exécutée.
  • Les FK peuvent faire des CASCADEchoses. (Personnellement, je préfère garder le contrôle et ne pas supposer que le FK fera la bonne chose.)

Conclusion pour les FK: certaines personnes insistent sur les FK; certains produits vivent parfaitement bien sans eux. Tu décides.

Se débarrasser d' PRIMARY KEYInnoDB est une grosse erreur. D'un autre côté, se débarrasser d'un substitut AUTO_INCREMENTet utiliser un PK «naturel» composé d'une (ou plusieurs) colonnes est souvent la bonne chose à faire. Un cas simple et courant est une table de correspondance plusieurs: plusieurs, comme indiqué ici .

Sur la base de mon expérience personnelle, je suggère que les 2/3 des tableaux préfèrent utiliser «naturel» au lieu de PK auto_inc.

Rick James
la source
1
Donc ... vous comptez sur une application presque parfaite car si un développeur fait une erreur avec un DELETEpar exemple et que vous n'avez pas de restriction côté DB, vous finirez par perdre des données. Cette approche est valide mais nécessite un code intense et de bons tests, ce qu'ils n'avaient pas :)
ReynierPM
Supprimer trop peut se produire dans l'application ou avec FK. Supprimer trop peu devient généralement évident. OTOH, j'ai vu des cas où supprimer trop peu vaut le coût - pensez à une "normalisation" où les choses sont rarement supprimées. Les rangées supplémentaires et inutilisées sont pratiquement inoffensives.
Rick James
J'ai vu un «bon» cas pour aucun index sur une table - une table intermédiaire pour une ingestion à grande vitesse. Il est très transitoire (d'où InnoDB non nécessaire) et n'a besoin d'être lu que complètement (par conséquent, aucun index n'est nécessaire).
Rick James
1
Notez un thème commun dans mes divagations: il n'y a pas de réponse unique; pas de taille unique.
Rick James
Si vos tables ont mille lignes de long; la performance n'est pas un problème. Si vos tables font un milliard de lignes, toutes les "règles" de normalisation, PK, index, FK, UUID, etc., doivent être examinées attentivement. Sinon, la base de données va fondre.
Rick James