web-dev-qa-db-fra.com

Dois-je définir les relations entre les tables dans la base de données ou simplement dans le code?

D'après mon expérience, la plupart des projets que j'ai lus dans le passé n'avaient pas de définitions de relations dans la base de données, au lieu de cela, ils les ont uniquement définies dans le code source. Je me demande donc quels sont les avantages/inconvénients de définir les relations entre les tables dans la base de données et dans le code source? Et la question plus large concerne les autres fonctionnalités avancées des bases de données modernes comme la cascade, les déclencheurs, les procédures ... Il y a certains points dans mes pensées:

Dans la base de données:

  • Données correctes de la conception. Empêchez les erreurs d'application qui peuvent provoquer des données invalides.

  • Réduisez l'aller-retour du réseau vers l'application lors de l'insertion/mise à jour des données car l'application doit effectuer plus de requêtes pour vérifier l'intégrité des données.

Dans le code source:

  • Plus flexible.

  • Mieux lors de la mise à l'échelle vers plusieurs bases de données, car parfois la relation peut être inter-base de données.

  • Plus de contrôle sur l'intégrité des données. La base de données n'a pas à vérifier chaque fois que l'application modifie des données (la complexité peut être O(n) ou O (n log n) (?)). Au lieu de cela, elle est déléguée à l'application. Et je pense que la gestion de l'intégrité des données dans l'application entraînera des messages d'erreur plus verbeux que l'utilisation de la base de données. Par exemple: lorsque vous créez un serveur API, si vous définissez les relations dans la base de données et que quelque chose se passe mal (comme l'entité référencée ne fait pas ' n'existe pas), vous obtiendrez une exception SQL avec un message. Le moyen le plus simple sera de renvoyer 500 au client qu'il y a une "erreur de serveur interne" et le client n'aura aucune idée de ce qui ne va pas. Ou le serveur peut analyser le message pour comprendre ce qui ne va pas, ce qui est à mon avis une méthode laide et sujette aux erreurs. Si vous laissez l'application gérer cela, le serveur peut générer un message plus significatif pour le client.

Y a-t-il autre chose?

Edit: comme le souligne Kilian, mon point sur les performances et l'intégrité des données est très erroné. J'ai donc édité pour corriger mon point là-bas. Je comprends parfaitement que laisser la base de données la gérer sera une approche plus efficace et plus robuste. Veuillez vérifier la question mise à jour et donner votre avis à ce sujet.

Edit: merci à tous. Les réponses que j'ai reçues indiquent toutes que les contraintes/relations doivent être définies dans la base de données. :). J'ai une autre question, car elle est tout à fait hors de portée de cette question, je viens de la poster comme une question distincte: Gérer l'erreur de base de données pour le serveur API . Veuillez laisser quelques informations.

60
Yoshi

TL; DR: les contraintes de relation doivent aller dans la base de données.


Votre application n'est pas assez grande.

Vous avez raison, en effet, que l'application des relations entre les bases de données peut nécessiter leur application dans l'application.

Je voudrais toutefois souligner que vous devez d'abord vérifier la documentation du logiciel de base de données que vous utilisez et vérifier les offres de produits existantes. Par exemple, il existe des offres de clustering en plus de Postgres et MySQL.

Et même si vous finissez par avoir besoin d'une validation dans l'application, ne jetez pas le bébé avec l'eau du bain =. Après tout, moins vous avez à faire, mieux vous vous portez.

Enfin, si vous êtes préoccupé par les futurs problèmes d'évolutivité, je crains que votre application doive subir des changements importants avant de pouvoir évoluer de toute façon. En règle générale, chaque fois que vous augmentez 10 fois, vous devez repenser ... alors ne dépensons pas trop d'argent pour ne pas anticiper les problèmes d'évolutivité, et utilisons plutôt de l'argent pour réellement atteindre le point où vous avez ces problèmes.

Votre application n'est pas assez correcte.

Quelle est la chance que la base de données que vous utilisez ait une implémentation défectueuse de la vérification par rapport à la chance que votre application ait une implémentation défectueuse de la vérification?

Et laquelle modifiez-vous le plus souvent?

Je parie que la base de données est correcte, à tout moment .

Vos développeurs ne pensent pas assez distribués.

Réduisez l'aller-retour du réseau vers l'application lorsque vous insérez/mettez à jour des données car l'application doit effectuer plus de requêtes pour vérifier l'intégrité des données.

Drapeau rouge!1

Si vous pensez:

  • vérifier si l'enregistrement existe
  • sinon, insérez l'enregistrement

alors vous avez échoué le problème de concurrence le plus élémentaire: un autre processus/thread pourrait ajouter l'enregistrement au fur et à mesure.

Si vous pensez:

  • vérifier si l'enregistrement existe
  • sinon, insérez l'enregistrement
  • vérifier si l'enregistrement a été inséré en double

alors vous n'avez pas pris en compte MVCC: la vue de la base de données que vous avez est un instantané au moment où votre transaction a commencé; il ne montre pas toutes les mises à jour en cours, et peut-être même pas validées.

Le maintien des contraintes sur plusieurs sessions est un problème très difficile, soyez content qu'il soit résolu dans votre base de données.

1  À moins que votre base de données n'implémente correctement la propriété Serializable; mais peu le font réellement.


Dernier:

Et je pense que gérer l'intégrité des données dans l'application permettra un message d'erreur plus détaillé que l'utilisation de la base de données. Par exemple: lorsque vous créez un serveur API. Si vous définissez des relations dans la base de données et que quelque chose ne va pas (comme l'entité référencée n'existe pas), vous obtiendrez une exception SQL avec un message.

Ne pas analyser les messages d'erreur, si vous utilisez une base de données de production, elle devrait renvoyer des erreurs structurées. Vous aurez au moins un code d'erreur pour indiquer ce qui est peut-être faux, et sur la base de ce code, vous pouvez créer un message d'erreur approprié.

Notez que la plupart du temps, le code est suffisant: si vous avez un code d'erreur vous indiquant qu'une clé étrangère référencée n'existe pas, il est probable que cette table ne possède qu'une seule clé étrangère, vous savez donc dans le code quel est le problème .

De plus, et soyons honnêtes ici, la plupart du temps, vous ne gérerez pas les erreurs avec élégance de toute façon. Tout simplement parce qu'il y en a tellement et que vous ne les expliquerez pas tous ...

... qui est juste lié au point de correction ci-dessus. Chaque fois que vous voyez une "500: Erreur de serveur interne" car une contrainte de base de données s'est déclenchée et n'a pas été gérée, cela signifie que la base de données vous a sauvé, car vous avez juste oublié de la gérer dans le code.

70
Matthieu M.

La base de données n'a pas à vérifier l'intégrité des données chaque fois que l'application modifie des données.

C'est un point profondément erroné. Des bases de données ont été créées précisément dans ce but. Si vous avez besoin de contrôles d'intégrité des données (et si vous pensez que vous n'en avez pas besoin, vous vous trompez probablement), alors laisser la base de données les gérer est presque certainement plus efficace et moins sujet aux erreurs que de le faire dans la logique d'application.

118
Kilian Foth

Les contraintes doivent se trouver dans votre base de données, car (avec la meilleure volonté du monde), votre application pas sera la seule chose à avoir jamais accédé à cette base de données.

À un moment donné, il peut être nécessaire de disposer d'un correctif scripté dans la base de données, ou vous devrez peut-être migrer les données d'une table vers une autre lors du déploiement.

De plus, vous pouvez obtenir d'autres exigences, par exemple "Le grand client X a vraiment besoin de cette feuille de données Excel importée dans notre base de données d'application cet après-midi", où vous n'aurez pas le luxe d'adapter votre code d'application en fonction du moment où un script SQL sale le fera à temps.

C'est là que l'intégrité au niveau de la base de données sauvera votre bacon.


De plus, imaginez le développeur qui prend votre rôle dans cette entreprise après votre départ et qui est ensuite chargé d'apporter des modifications à la base de données.

Va-t-il vous détester s'il n'y a pas de contraintes FK dans la base de données afin qu'il puisse dire quelles relations une table a avant de la changer? ( Indice, la réponse est oui )

51
Paddy

Vous devez avoir des relations dans la base de données.

Comme le note l'autre réponse, les performances de la vérification des contraintes seront bien meilleures à l'intérieur de cette base de données qu'à l'intérieur de votre application. Les vérifications de contraintes de base de données sont l'une des qualités des bases de données.

Si vous avez besoin d'une flexibilité supplémentaire, par exemple vos références de bases de données croisées notées - alors vous pouvez supprimer les contraintes délibérément et avec considération. La cohérence de votre base de données signifie que vous avez la possibilité de modifier ces contraintes et la certitude de l'intégrité référentielle.

17
Kirk Broadhurst
  • Nous ne vivons plus dans un seul back-end <-> un seul front-end.
  • La plupart des solutions impliquent un frontal Web, un frontal mobile, un frontal par lots et un frontal iPad, etc.
  • Les moteurs de base de données ont déjà des milliers de lignes de code testées optimisées pour appliquer l'intégrité référentielle.

Pouvez-vous vraiment vous permettre d'écrire et de tester le code d'application de l'intégrité référentielle lorsque vous avez du code de résolution de problèmes de domaine à écrire?

13
Tulains Córdova

Si vous ne validez pas l'intégrité de vos données, les contraintes, les relations, etc. au niveau de la base de données, cela signifie qu'il est beaucoup plus facile pour quiconque ayant accès à la base de données de production (via tout autre client, y compris un outil d'accès à la base de données) de gâcher vos données.

Il est recommandé d'appliquer l'intégrité des données la plus stricte possible au niveau de la base de données. Croyez-moi, cela vous évitera d'énormes maux de tête au fil du temps dans tout système non trivial. Vous pourrez également détecter plus rapidement les erreurs de logique d'application ou les erreurs et incohérences liées aux exigences métier si vous y réfléchissez attentivement.

En remarque, concevez votre base de données de manière aussi normalisée et atomique que possible. Pas de tables "Dieu". Passez beaucoup d'efforts à concevoir votre base de données pour qu'elle soit aussi simple que possible, idéalement avec de nombreuses petites tables qui sont individuellement très bien définies, avec une seule responsabilité et soigneusement validées sur toutes les colonnes. La base de données est le dernier gardien de l'intégrité de vos données. Il représente le donjon du château.

2
Brad Thomas

La plupart des gens disent essentiellement "oui, en général tu devras toujours définir les relations dans la base de données". Mais si les disciplines de l'informatique étaient si faciles, nous serions appelés "lecteurs manuels de logiciels" au lieu de "ingénieurs logiciels". Je suis en fait d'accord pour dire que les contraintes doivent aller dans la base de données, à moins qu'il n'y ait une bonne raison pour qu'elles ne le fassent pas , alors permettez-moi de fournir quelques raisons qui pourrait être considérée bonne dans certaines situations:

Code en double

Parfois, une certaine quantité de fonctionnalités pouvant être gérées par la base de données existe naturellement dans le code d'application. Si ajouter quelque chose comme des contraintes à la base de données serait redondant, il serait préférable de ne pas dupliquer la fonctionnalité, car vous violez les principes DRY, et vous pourriez aggraver l'acte de jonglerie consistant à conserver la base de données et code d'application synchronisé.

Effort

Si votre base de données fait déjà ce qu'elle doit faire sans utiliser de fonctionnalités avancées, vous voudrez peut-être évaluer où votre temps, votre argent et vos efforts doivent être placés. Si l'ajout de contraintes empêcherait une défaillance catastrophique et ferait ainsi économiser beaucoup d'argent à votre entreprise, cela en vaut probablement la peine. Si vous ajoutez des contraintes qui devraient tenir, mais qui sont déjà garanties de ne jamais être violées, vous perdez du temps et polluez votre base de code. Garanti est le mot clé ici.

efficacité

Ce n'est normalement pas une bonne raison, mais dans certains cas, vous pourriez avoir une certaine exigence de performance. Si le code d'application peut implémenter une certaine fonctionnalité plus rapidement que la base de données et que vous avez besoin de performances supplémentaires, vous devrez peut-être implémenter la fonctionnalité dans le code d'application.

Contrôle

Relativement lié à l'efficacité. Parfois, vous avez besoin d'un contrôle extrêmement fin sur la façon dont une fonctionnalité est implémentée, et parfois, la gestion de la base de données la cache derrière une boîte noire que vous devez ouvrir.

Points de fermeture

  • Les bases de données sont écrites en code. Il n'y a rien de magique qu'ils font que vous ne pouvez pas faire dans votre propre code.
  • Rien n'est gratuit. Les contraintes, relations, etc. utilisent toutes des cycles CPU.
  • Les gens du monde NoSQL s'entendent très bien sans les fonctionnalités relationnelles traditionnelles. Dans MongoDB par exemple, la structure des documents JSON est suffisamment bonne pour prendre en charge une base de données entière.
  • L'utilisation aveugle et ignorante des fonctionnalités avancées de la base de données ne peut garantir aucun avantage. Vous pourriez accidentellement faire fonctionner quelque chose pour le casser plus tard.
  • Vous avez posé une question très générale sans énumérer les exigences ou contraintes spécifiques. La vraie réponse à votre question est "ça dépend".
  • Vous n'avez pas spécifié s'il s'agissait d'un problème à l'échelle de l'entreprise. D'autres réponses parlent de choses comme les clients et l'intégrité des données, mais parfois ces choses ne sont pas importantes.
  • Je suppose que vous parlez d'une base de données relationnelle SQL traditionnelle.
  • Ma perspective vient d'avoir cessé d'utiliser des tonnes de contraintes et de clés étrangères dans de petits projets (jusqu'à 50 tables), et de ne pas remarquer d'inconvénients .

La dernière chose que je dirai, c'est que vous saurez si vous ne devez pas placer la fonctionnalité dans la base de données. Si vous n'êtes pas sûr, vous feriez probablement mieux d'utiliser les fonctionnalités de la base de données, car elles fonctionnent généralement très bien.

1
parker.sikand

Vous avez de très bonnes réponses mais quelques points supplémentaires

L'intégrité des données est l'objectif d'une base de données

Faire une concurrence appropriée comme une suppression FK au niveau de l'application serait horrible

L'expertise en intégrité des données est avec un DBA

Au niveau du programme, vous insérez, mettez à jour, mettez à jour en bloc, insérez en bloc, supprimez en bloc ...
Client léger, client lourd, client mobile ....
L'intégrité des données n'est pas l'expertise d'un programmeur - beaucoup de code en double et quelqu'un va le gâcher

Supposons que vous soyez piraté - vous avez des ennuis de toute façon, mais un pirate peut faire beaucoup de dégâts via un petit trou s'il n'y a pas de protection d'intégrité dans la base de données

Vous devrez peut-être manipuler des données directement via SQL ou TSQL
Personne ne se souviendra de toutes les règles de données

0
paparazzo

Votre question n'a pas de sens: si vous pouvez changer la base de données, c'est du code, si vous ne pouvez pas changer la base de données, vous devrez créer vos contraintes ailleurs.

Une base de données que vous pouvez modifier est autant de code que n'importe quelle ligne de Ruby, javascript, c # ou ada.

La question de savoir où placer une contrainte dans votre système devrait se résumer à la fiabilité, le coût et la facilité de développement.

0
jmoreno

Comme toujours, il existe de nombreuses réponses. Pour moi, j'ai trouvé une règle simple (enfin cela ne fonctionne que pour une approche centrée sur le modèle). Habituellement, je me concentre uniquement sur les différentes couches d'applications.

Si le modèle se compose de plusieurs entités et qu'il existe des dépendances entre les entités, la couche de persistance doit refléter ces dépendances avec ses possibilités. Donc, si vous utilisez un SGBDR, vous devez également utiliser des clés étrangères. La raison est simple. De cette façon, les données sont toujours valides selon la structure.

Toute instance effectuant un travail sur cette couche de persistance peut y compter. Je suppose que vous encapsulez cette couche via l'interface (service). Voici donc le point où la conception se termine et où le monde réel commence.

En regardant vos points, en particulier références croisées. Dans ce cas, oui, il ne devrait pas y avoir de référence implémentée dans le SGBDR lui-même, mais dans le service. Mais avant de suivre cette voie, ne serait-il pas préférable de considérer cela déjà lors de la conception?

Signifie, si je sais déjà, qu'il y a des pièces qui doivent être stockées dans une autre base de données, alors je peux les mettre déjà là et le définir comme modèle séparé. Droite?

Vous signalez également que l'implémentation de cela dans le code est plus flexible. D'accord, mais ne semble-t-il pas que vous ayez affaire à une conception incomplète? Demandez-vous pourquoi avez-vous besoin de plus de flexibilité?

Le problème de performances, dû à vérifications d'intégrité dans DB n'est pas réel. Le SGBDR peut vérifier de telles choses beaucoup plus rapidement que n'importe quelle implémentation de votre part. Pourquoi? Eh bien, vous devez faire face à la perturbation des médias, pas le SGBDR. Et il peut optimiser ces contrôles en utilisant ses statistiques a.s.o.

Donc, vous voyez, tout revient au design. Bien sûr, vous pouvez dire maintenant, mais que se passe-t-il si une exigence inconnue apparaît, un changeur de jeu? Oui, cela pourrait arriver, mais de tels changements devraient être conçus et planifiés a.s.o ..; o)

0
DHN

Il y a des tonnes de bonnes réponses ici. J'ajouterai que si vous avez une application écrite en langage Y, vous pouvez créer du code de type contrainte de base de données en Y. Et puis quelqu'un veut accéder à votre base de données en utilisant le langage Z, vous devrez réécrire le même code. Dieu vous aide si les implémentations ne sont pas exactement les mêmes. Ou lorsqu'un utilisateur professionnel averti se connecte à votre base de données à l'aide de Microsoft Access.

Mon expérience me dit que lorsque les gens ne veulent pas utiliser les contraintes de base de données, c'est parce qu'ils essaient en fait de faire quelque chose de mal. Par exemple, ils essaient de charger des données en bloc, et ils veulent laisser les colonnes non nulles pendant un certain temps. Ils ont l'intention de "corriger cela plus tard" parce que la situation qui a rendu la contrainte non nulle critique "ne peut pas se produire dans ce cas". Un autre exemple pourrait être lorsqu'ils essaient de combiner deux types de données différents dans la même table.

Les personnes plus expérimentées prendront du recul et trouveront une solution qui n'implique pas d'essayer de contourner une contrainte. La solution pourrait simplement être que la contrainte n'est plus appropriée car l'entreprise a bien sûr changé.

0
Tony Ennis