Pourquoi des contraintes sont-elles appliquées dans la base de données plutôt que dans le code?

21

Pourquoi la contrainte est-elle appliquée dans la base de données? Ne sera-t-il pas plus flexible de le mettre dans le code?

Je lis un livre pour débutants sur la mise en œuvre de bases de données, donc je pose la question en tant que débutant. Disons que j'ai conçu une base de données, y compris ce modèle d'entité:

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

Contraintes actuelles:

  1. Une personne inscrite sur le système ne peut être qu'un étudiant ou un employé.
  2. L'entité personne requiert l'unicité du numéro social, que nous supposons que chaque personne n'en détient qu'une seule unique (aka, une clé primaire suffisamment bonne ). (voir # 1)

Plus tard, nous décidons de supprimer le numéro 1: si un jour le collège décide que le Teacher(le Employeesous-type) peut également l'être Student, en prenant des cours pendant leur temps libre, il est beaucoup plus difficile de changer la conception de la base de données qui pourrait avoir des milliers, des millions, des milliards, des millions d'entrées plutôt que de simplement changer la logique dans le code: juste la partie qui ne permettait pas à une personne d'être inscrite à la fois comme étudiant et comme employé.

(C'est très improbable mais je ne peux penser à rien d'autre pour le moment. Apparemment, c'est possible).

Pourquoi nous soucions-nous des règles métier dans la conception des bases de données plutôt que dans le code?

# 1: Une note 7 ans plus tard, un exemple concret:
j'ai vu un gouvernement où en raison d'une erreur, les SSN émis étaient dupliqués: plusieurs personnes, même SSN. Les concepteurs de la base de données d'origine ont définitivement commis cette erreur en n'appliquant pas cette contrainte d'unicité dans la base de données. (et plus tard un bogue dans l'application d'origine? plusieurs applications utilisant la base de données partagée et ne convenant pas où mettre, vérifier et appliquer la contrainte? ...).
Ce bogue continuera à vivre dans le système et tout le système développé après quoi s'appuiera sur la base de données de ce système d'origine, pendant de nombreuses années à venir. En lisant les réponses ici, j'ai appris à appliquer toutes les contraintes, autant que possible, à bon escient (pas aveuglément) dans la base de données pour représenter le monde physique réel là-bas aussi bien que possible.

hkoosha
la source
2
Surtout, nous nous soucions de l'application des règles commerciales et de la meilleure façon d'y parvenir.
ypercubeᵀᴹ
3
Vous présentez en fait un très mauvais exemple de l'utilisation des contraintes, car la flexibilité de vos entités et l'extensibilité de la base de données sont principalement définies par la normalisation. Cela dit, les contraintes sont la dernière protection contre toute donnée corrompue entrant dans la base de données, même si l'application est bogue, même si une nouvelle application est développée, même si une API externe est ajoutée, même si quelqu'un modifie directement la base de données. Des contraintes gardent la base de données, en plus de cela, la logique métier devra également faire ses propres choses avant d'essayer d'accéder à la base de données.
Niels Keurentjes
3
En fait, en tant qu'étudiant diplômé, je suis considéré à la fois comme un étudiant, un employé et un enseignant. Votre exemple n'est donc pas vraiment improbable.
Winston Ewert
4
Vous ne devez jamais baser une conception de base de données sur les objets de votre application. Vous devez normalement concevoir cela comme une personne, puis avoir un tableau associé pour définir les rôles des personnes. Ensuite, le problème ne se pose pas car vous avez créé une table pour les rôles afin que les personnes puissent avoir plusieurs rôles. Si vous ne souhaitez avoir qu'une seule personne de rôle, vous contraignez la table de sorte que l'ID de personne soit unique. Lorsque vous voulez changer cela, supprimez la contrainte.
HLGEM
L'objet <-> La cartographie relationnelle est un art.
Thorbjørn Ravn Andersen

Réponses:

34

Certaines contraintes sont mieux appliquées dans la base de données et d'autres sont mieux appliquées dans l'application.

Les contraintes qui sont mieux appliquées dans la base de données sont généralement présentes car elles sont fondamentales pour la structure du modèle de données, comme une contraint de clé étrangère pour garantir la validité d'un produit category_id.

Les contraintes qui sont appliquées dans une application peuvent ne pas être fondamentales pour le modèle de données, comme tous les produits FooBar doivent être bleus - mais plus tard, quelqu'un pourrait décider que FooBars peut également être jaune. Il s'agit d'une logique d'application qui n'a pas vraiment besoin d'être dans la base de données, mais vous pouvez créer une colourstable distincte et la base de données peut exiger que le produit fasse référence à une entrée valide de cette table. MAIS la décision que le seul enregistrement dans coloursa la valeur blueproviendrait encore de quelque part en dehors de la base de données.

Considérez ce qui se passerait si vous n'aviez aucune contrainte dans la base de données et exigiez qu'elles soient toutes appliquées dans l'application. Que se passerait-il si vous aviez plus d'une application qui devait travailler avec les données? À quoi ressembleraient vos données si les différentes applications décidaient d'appliquer différemment les contraintes?

Votre exemple montre une situation où il aurait été plus avantageux d'avoir la contrainte dans l'application plutôt que dans la base de données, mais peut-être y avait-il un problème fondamental avec le modèle de données initial étant trop restrictif et rigide?

FrustratedWithFormsDesigner
la source
Ainsi, selon cette réponse, la règle <une personne ne peut exister que dans la table de sous-type Étudiant ou uniquement dans la table de sous-type Employés> doit être appliquée dans le code, Et la base de données a <Le sous-type Étudiant / Employé doit être valide personne> contrainte. Ai-je raison? (C'était l'exemple du livre). Merci.
hkoosha
2
@loolooyyyy: Oui, je pense que c'est correct. Si la base de données applique la première règle (qu'une personne ne peut être qu'un étudiant ou un employé), alors la situation que vous avez décrite (dans laquelle un employé veut s'inscrire à un cours) est impossible parce que: la personne ne peut pas être les deux, et ce n'est pas il est même possible de créer un deuxième enregistrement de «personne» car ils ne peuvent pas partager les numéros de sécurité sociale qui sont probablement émis par un tiers (comme le gouvernement). Bien sûr, ce modèle de données trop restrictif peut fonctionner dans certains cas ...
FrustratedWithFormsDesigner
2
@loolooyyyy: Une autre façon d'utiliser le modèle de données d'origine et de laisser les enseignants être des étudiants pourrait être d'appeler une autre table teachers_as_studentsqui est un autre sous-type de Studentset a une nouvelle clé étrangère en référence Teacherset une clé primaire générée par le système , au lieu d'une Social Numéro de sécurité. De cette façon, un "élève" est en fait un alias pour un enseignant afin que l'enseignant puisse toujours s'inscrire pour suivre un cours. Il est difficile de dire avec certitude dans quelle mesure cela fonctionnerait sans voir l'ensemble du modèle de données.
FrustratedWithFormsDesigner
2
J'ai rétrogradé cela. Il n'y a aucun moment où une contrainte est mieux appliquée dans l'application uniquement. Le ton de cette réponse n'est pas pondéré correctement.
Evan Carroll du
3
@FrustratedWithFormsDesigner certainement, c'est en fait l'enfant poster pour une contrainte de clé étrangère. Supposons que vous ayez trois clients de versions / builds différentes du point d'accès db, qu'allez-vous faire lorsque vous cessez d'expédier ce produit en rouge? Où allez-vous stocker la liste des combinaisons de couleurs possibles ? Astuce: j'ai un endroit centralisé pour vous. Et si vous créez la table color_products, et color, vous pourrez probablement créer les listes déroulantes supplémentaires avec plus de facilité - la plupart des IDE / chargeurs de schéma, prennent en charge les fkeys suivants.
Evan Carroll du
35

Car:

  1. Je veux que toutes les données de la base de données soient soumises aux mêmes contraintes, pas seulement les nouvelles données soient soumises aux contraintes de la version du code en cours d'exécution aujourd'hui.
  2. Je veux des contraintes déclaratives, pas des contraintes programmatiques.
  3. Les données de la base de données survivent souvent au code écrit pour interagir avec elles aujourd'hui. Et ces données - pas le code - sont les atouts de l'organisation.
  4. Mon code devient beaucoup plus simple quand je sais que toutes les données sont soumises à des contraintes rigoureuses. Je n'ai plus à considérer de cas particuliers dont je sais que la base de données garantit d'être impossible.

Juste quelques raisons qui sont importantes pour moi.

Colin 't Hart
la source
4
Semi-liés à (1) et (3): les bogues dans le code d'application peuvent être corrigés, les bogues dans vos données sont souvent irréparables.
mu est trop court
17

Les données survivront probablement longtemps au code d'application. Si la règle est essentielle à l'utilité des données dans le temps (comme les contraintes de clé étrangère qui aident à maintenir l'intégrité des données), elle doit se trouver dans la base de données. Sinon, vous risquez de perdre la contrainte dans une nouvelle application qui frappe la base de données. Non seulement plusieurs applications atteignent les bases de données (y compris certaines qui ne réalisent pas qu'il existe une règle de données importante), mais certaines d'entre elles telles que les importations de données ou les applications de génération de rapports peuvent ne pas être en mesure d'utiliser la couche de données configurée dans l'application principale de saisie de données. Franchement, les chances qu'il y ait un bogue dans la contrainte sont beaucoup plus élevées dans le code d'application selon mon expérience.

À mon avis personnel (sur la base de plus de 30 ans de traitement des données et de l'expérience avec des centaines de bases de données différentes utilisées à de nombreuses fins différentes), quiconque ne place pas les contraintes dans la base de données à laquelle il appartient aura finalement des données médiocres. Parfois de mauvaises données au point d'être inutilisables. Cela est particulièrement vrai lorsque vous disposez de données financières / réglementaires qui doivent répondre à certains critères d'audit.

HLGEM
la source
17

La plupart des contraintes d'intégrité référentielle qui sont implémentées en dehors de la base de données peuvent être supprimées, donc si vous voulez que vos données aient une intégrité garantie à tout moment, vous devez appliquer des contraintes dans la base de données. Arrêt complet, c'est tout.

En règle générale, les contraintes au niveau de l'application sont supprimées via le mécanisme de cohérence de lecture de la base de données, par lequel les sessions ne peuvent pas afficher les données des autres sessions jusqu'à ce qu'elles soient validées.

Par exemple, deux sessions peuvent essayer d'insérer la même valeur dans une colonne destinée à être unique. Ils peuvent tous deux vérifier en même temps que la valeur n'existe pas déjà, peuvent à la fois insérer leur valeur et peuvent tous les deux valider. Une contrainte unique implémentée dans la base de données ne laisserait pas cela se produire.

Au fait, cela n'est pas inconnu des concepteurs de langage d'application. Lisez la section 3.10 unicité dans les guides Ruby on Rails: validations d'enregistrements actifs et rappels

Cet assistant valide que la valeur de l'attribut est unique juste avant que l'objet soit enregistré. Il ne crée pas de contrainte d'unicité dans la base de données, il peut donc arriver que deux connexions de base de données différentes créent deux enregistrements avec la même valeur pour une colonne que vous souhaitez être unique. Pour éviter cela, vous devez créer un index unique dans votre base de données.

David Aldridge
la source
16

Avantages des contraintes imposées par la base de données:

Simplicité - Déclarer une contrainte est beaucoup plus simple que de déclarer une contrainte et d'écrire le code qui appliquera cette déclaration.

Précision - Le code que vous n'avez pas écrit n'aura jamais de bug que vous avez créé. Les fournisseurs de bases de données passent du temps à s'assurer que leur code de contrainte est précis, vous n'avez donc pas à le faire.

Vitesse - Votre application ne peut jamais avoir plus de distributions que la base de données sur laquelle elle est basée. Les fournisseurs de bases de données passent du temps à s'assurer que leur code de contrainte est efficace, vous n'avez donc pas à le faire. La base de données elle-même a également un accès plus rapide aux données qu'une application ne pourrait jamais avoir, peu importe son efficacité.

Réutilisation - Vous pouvez commencer avec une seule application sur une seule plate-forme, mais cela peut ne pas rester ainsi. Et si vous avez besoin d'accéder aux données à partir d'un système d'exploitation différent, d'un matériel différent ou d'une interface vocale? En ayant des contraintes dans la base de données, ce code n'a jamais à être réécrit pour la nouvelle plate-forme et n'a jamais à être débogué pour la précision ou profilé pour la vitesse.

Exhaustivité - Les applications imposent des contraintes lorsque les données sont entrées dans la base de données et nécessiteraient des efforts supplémentaires pour vérifier l'exactitude des données plus anciennes ou pour manipuler les données déjà présentes dans la base de données.

Longévité - Votre plate-forme de base de données survivra probablement à toute application particulière.

Leigh Riffel
la source
11

Pourquoi des contraintes sont-elles appliquées sur le serveur? Parce que vous ne pouvez pas forcer les méchants à utiliser votre client.

Pour clarifier, si vous ne faites que le traitement des règles métier dans votre application client, une personne utilisant un autre outil peut se connecter au serveur de base de données et faire ce qu'elle veut sans être contraint par l'une de vos règles métier et des contrôles d'intégrité. Il est très difficile d'empêcher quiconque d'utiliser un outil arbitraire n'importe où sur le réseau.

Si vous effectuez la vérification d'intégrité sur le serveur de base de données, chaque tentative d'accès aux données, quel que soit l'outil, sera limitée par vos règles.

Marcheur de Greenstone
la source
10

Quelques bonnes réponses ici, et au risque de répéter d'autres pensées:

  • Le SSN n'est pas nécessairement unique. Heck, SSN n'est même pas toujours connu, et dans certains cas, il n'existe pas (encore). Les SSN peuvent être réutilisés et tous les employés ou étudiants peuvent ne jamais avoir de SSN. Ceci est périphérique à la question, mais démontre que, peu importe où vous imposez vos contraintes, vous devez comprendre le modèle de données et le domaine de manière assez approfondie pour prendre des décisions sur les règles métier.
  • Personnellement, je préfère que les contraintes soient aussi proches que possible des données. La raison très simple est que tout le monde n'utilisera pas le code d'application pour modifier les données de la base de données. Si vous appliquez vos règles métier au niveau de l'application et que je lance une UPDATEinstruction directement sur la base de données, comment votre application empêche-t-elle une modification non valide? Un autre problème avec les règles métier dans l'application est que la recompilation / redéploiement peut être difficile, en particulier pour les applications distribuées où il est possible que tout le monde ne reçoive pas la mise à jour en même temps. Et enfin, la modification des règles métier dans l'application ne fait absolument rien sur les données existantes qui violent les nouvelles règles - si vous ajoutez la nouvelle contrainte aux données, vous devez corriger les données.
  • Vous pourrez peut-être justifier plusieurs contrôles redondants à différents niveaux. Tout cela dépend de la flexibilité des méthodologies de déploiement, de la probabilité d'un changement et de la difficulté de synchroniser un changement de règle métier dans la base de données et d'autres couches. Un argument convaincant pour répéter les vérifications au niveau de la couche d'application est que vous pouvez potentiellement empêcher un aller-retour vers la base de données uniquement pour y échouer une contrainte (selon la nature de la contrainte et si elle repose sur des données existantes). Mais si je devais choisir l'un ou l'autre, je le mettrais dans la base de données pour les raisons ci-dessus.

Dans le cas que vous mentionnez explicitement, où vous autorisez soudainement quelque chose qui n'était pas autorisé auparavant, ce n'est pas vraiment un problème - vous supprimez toutes les contraintes qui l'ont imposé, peu importe où cela existe. Dans le cas contraire, où soudainement les enseignants ne sont plus autorisés à être des étudiants, vous avez potentiellement un tas de données à nettoyer, là encore indépendamment de l'endroit où la contrainte existait auparavant.

Aaron Bertrand
la source
9
  1. La base de données peut vérifier efficacement les contraintes. Mieux que le code.

  2. Les contraintes d'intégrité aident la base de données à trouver un plan d'exécution efficace

  3. L'application voit une vue cohérente en lecture, donc elle peut difficilement garantir l'unicité. La base de données peut également voir des données non validées.

ibre5041
la source
8

Réponse courte ... pour préserver l'intégrité des données (c'est-à-dire l'exactitude et la validité).

Une exception ...
Si la base de données stocke simplement les données d'une seule application pour un seul utilisateur, comme dans la plupart des bases de données Sqlite, elle peut ne pas avoir besoin de contraintes. En fait, ils ne le font généralement pas, afin de garder le temps d'accès si rapide qu'il est incommensurable.

Pour tout le reste ... Les
bases de données servent toujours deux maîtres que j'appellerai éditeurs et utilisateurs .

Les éditeurs mettent principalement des données dans la base de données et récupèrent les données un ou un petit nombre d'enregistrements à la fois. Leurs principales préoccupations sont un accès rapide et précis à toutes les données associées et un stockage rapide et fiable de leurs modifications.

Les utilisateurs récupèrent principalement des données et sont plus soucieux d'un accès rapide à des informations incontestablement précises. Ils ont souvent besoin de divers comptes, agrégations et listes qui étaient auparavant générés dans ces piles emblématiques d'une épaisseur d'un pied d'impressions de papier barre verte, mais qui se retrouvent généralement sur les pages Web aujourd'hui.

Les projets de développement de bases de données sont presque toujours lancés à la demande des utilisateurs , mais la conception est motivée par les besoins de saisie des données et d'enregistrement à la fois des éditeurs . Ainsi, les développeurs inexpérimentés répondent souvent au besoin immédiat de rapidité (principalement de développement ) en ne mettant pas de contraintes dans la base de données.

Si une et une seule application doit être utilisée pour apporter des modifications aux données pendant toute la durée de vie de la base de données, et que cette application est développée par une ou un petit nombre d'individus bien coordonnés, alors il pourrait être raisonnable de s'appuyer sur l'application pour assurer l'intégrité des données.

Cependant, autant que nous prétendons pouvoir prédire l'avenir, nous ne le pouvons pas.

L'effort pour produire une base de données est trop précieux pour la jeter. Comme une maison, la base de données sera agrandie, modifiée et rénovée plusieurs fois. Même lorsqu'elle est complètement remplacée, toutes les données seront migrées vers la nouvelle base de données tout en préservant toutes les anciennes règles et relations commerciales.

Les contraintes implémentent ces règles et relations sous une forme déclarative concise dans le moteur de base de données lui-même où elles sont facilement accessibles. Sans eux, les développeurs ultérieurs devraient parcourir les programmes d'application pour procéder à une rétro-ingénierie de ces règles. Bonne chance!

D'ailleurs, c'est exactement ce que les programmeurs COBOL mainframe doivent faire, car ces bases de données massives ont souvent été créées avant que nous ayons des moteurs relationnels et des contraintes. Même en cas de migration vers un système moderne comme DB2 d'IBM, les contraintes ne sont parfois pas entièrement mises en œuvre car la logique des anciennes règles, incorporées peut-être dans une série de programmes "batch" COBOL, peut être si compliquée qu'elle n'est pas pratique à convertir. Des outils automatisés peuvent à la place être utilisés pour convertir l'ancien COBOL en une version plus récente avec des interfaces vers le nouveau moteur relationnel et avec un petit ajustement, l'intégrité des données est préservée ... jusqu'à ce qu'une nouvelle application soit écrite qui corrompt subtilement tout et que l'entreprise soit transportée en justice pour, disons, empêcher des milliers de propriétaires de maison qu'ils ne devraient pas avoir.

DocSalvager
la source
7

En plus des autres commentaires ...

Si / lorsque vous avez une base de données où une table donnée peut être mise à jour par une ou plusieurs applications ou chemins de code, le fait de placer les contraintes appropriées dans la base de données signifie que vos applications ne dupliqueront pas le "même" code de contrainte. Cela vous profite en simplifiant la maintenance (en réduisant le nombre d'emplacements à modifier en cas de changement de modèle de données) et en garantissant que les contraintes sont appliquées de manière cohérente quelle que soit l'application mettant à jour les données.

gsiems
la source
5

Personnellement, je pense qu'il est plus facile de créer et de modifier des contraintes que de créer des déclencheurs, par exemple, ce qui serait un moyen d'appliquer votre règle métier à l'aide du code source.

Les déclencheurs sont également moins susceptibles d'être portables, car ils sont généralement écrits dans des langages spécifiques au fournisseur, tels que PL / SQL.

Mais si les contraintes ne répondent pas à vos besoins, vous pouvez toujours utiliser des déclencheurs pour appliquer vos règles métier.

perle
la source
5
De plus, les déclencheurs ne garantissent pas l'intégrité, en raison de problèmes de cohérence de lecture.
David Aldridge
3

Ils doivent toujours être appliqués dans la base de données en premier parce que,

  1. La base de données garantit l'intégrité entre les différents clients. Vous pouvez avoir différents clients sur différentes plateformes pour accéder à la base de données. Les contraintes dans la base de données ne risquent pas de problèmes d'intégrité lorsque vous créez un nouveau client. Cela vous évite d'avoir à Q / A vos contraintes en cas de réécriture ou d'un point d'accès supplémentaire.
  2. La base de données possède un DSL pour construire des contraintes: SQL DDL!
  3. La base de données permet d'accéder à ces contraintes dans les catalogues système afin qu'un ORM ou un "chargeur de schéma" approprié puisse lire ces contraintes et les intégrer à votre application. Par exemple, si votre base de données spécifie que vous avez un varchar(5)type, il y a de fortes chances que vous puissiez trouver un schéma de chargement ORM pour votre langue spécifique qui mappe le type de langue au type de schéma et assemble sa propre contrainte de taille. DBIx for Perl is one such schema loader; en voici une autre pour Entity Framework . Les capacités de ces chargeurs varient, mais tout ce qu'ils peuvent fournir est un bon début pour assurer l'intégrité de l'application sans se rendre à la base de données.
Evan Carroll
la source