Disons que j'ai le diagramme ER suivant:
Maintenant, si je représentais la relation à l'aide d'une clé étrangère de School
in Student
, je pourrais avoir des NULL
valeurs (car il Student
n'est pas nécessaire que a appartienne à a School
), par exemple:
Donc, la bonne façon (basée sur ce que j'ai lu) est de créer une table d'intersection pour représenter la relation, par exemple:
De cette façon, aucune NULL
valeur ne peut être présente dans le tableau School_has_Student
.
Mais quels sont les inconvénients de l'utilisation d'une clé étrangère nullable au lieu de créer une table d'intersection?
Éditer:
J'ai par erreur choisi ( school_id
, student_id
) pour être la clé primaire de la School_has_Student
table, ce qui a rendu la relation plusieurs à plusieurs. La clé primaire correcte aurait dû être student_id
:
Réponses:
Les deux modèles représentent des relations différentes.
En utilisant une table de jointure, vous modélisez une relation plusieurs-à-plusieurs.
En utilisant une simple clé étrangère, vous modélisez une relation un-à-plusieurs.
L'inconvénient d'une clé étrangère annulable est de ne pas pouvoir modéliser la relation en plusieurs à plusieurs, si c'est ce que vous essayez d'accomplir.
En fonction de votre modification de la question, vous divisez efficacement la table des élèves en deux tables avec la même clé. Je vois généralement cela sur des tables qui ont beaucoup trop de champs, donc quelqu'un les divise en deux pour être plus faciles à gérer (je l'appelle mettre du rouge à lèvres sur un cochon).
En fractionnant la table des étudiants, vous rendez la deuxième table facultative car il n'est pas nécessaire qu'un enregistrement existe dans la deuxième table. Ce qui est très similaire à un champ qui n'a pas besoin d'être défini car il peut être nul.
Si vous souhaitez une relation un-à-plusieurs, il est préférable d'utiliser une seule table et de permettre que l'ID de l'école soit nul dans la table des étudiants. Il n'y a aucune raison d'éviter les null dans les champs, même pour une clé étrangère. Cela signifie que la relation étrangère est facultative: les développeurs et les administrateurs de base de données le comprennent clairement, et le moteur de base de données sous-jacent devrait certainement fonctionner correctement.
Si vous êtes préoccupé par les jointures, ne vous inquiétez pas. Il existe une sémantique bien définie sur la façon dont les jointures fonctionnent avec les champs nuls. En utilisant une seule table, vous pouvez joindre deux tables au lieu de trois.
la source
NULL
valeurs?student_id
qu'une clé primaire dans leSchool_has_Student
tableau, ce qui a conservé la relation un-à-plusieurs. Quels sont les inconvénients de cette méthode par rapport à l'utilisation d'une clé étrangère?Vous avez écrit dans un commentaire ci-dessus:
Lorsqu'il y a beaucoup de valeurs NULL dans la colonne de clé étrangère, vos programmes devront traiter cette colonne, pour la plupart vide, pour chaque enregistrement qu'ils traitent. La colonne occupera probablement un peu d'espace disque même si dans 98% de tous les cas elle est vide, interroger la relation signifie interroger cette colonne qui vous donne plus de trafic réseau, et si vous utilisez un ORM qui vous génère des classes à partir de vos tables, de vos programmes aura également besoin de plus d'espace côté client que nécessaire. L'utilisation d'une table d'intersection évite cela, il n'y aura que des enregistrements de lien nécessaires où la clé étrangère équivalente ne serait pas NULL sinon.
En revanche, si vous n'avez pas seulement quelques valeurs NULL, disons que 50% ou plus de relations ne sont pas NULL, l'utilisation d'une table d'intersection vous donne l'effet inverse - plus d'espace disque, une complexité plus élevée entraînant plus de trafic réseau, etc.
Ainsi, l'utilisation d'une table d'intersection n'est qu'une forme d'optimisation, uniquement judicieuse pour un cas spécifique, et en particulier de nos jours, où l'espace disque et la mémoire sont devenus moins chers, et beaucoup moins souvent nécessaires. Notez que "Fundamentals of Database Systems" a été écrit à l'origine il y a plus de 20 ans (j'ai trouvé une référence à la deuxième édition de 1994), et je suppose que cette recommandation était déjà là à l'époque. Avant 1994, l'optimisation de l'espace était probablement beaucoup plus importante qu'aujourd'hui, car le stockage de masse était encore plus cher et les ordinateurs et les réseaux étaient beaucoup plus lents qu'aujourd'hui.
En guise de note complémentaire à un commentaire pointilleux: la déclaration ci-dessus tente simplement d'anticiper ce que l'auteur de "Fundamentals of Database Systems" avait à l'esprit avec sa recommandation, je suppose qu'il faisait une déclaration générale approximative, valable pour la plupart des systèmes. Dans certaines bases de données, il existe d'autres optimisations possibles, comme des "colonnes éparses", qui rendent l'utilisation d'une table d'intersection encore plus obsolète.
Alors, ne vous méprenez pas sur cette recommandation. Le livre ne vous dit pas de préférer les tables d'intersection pour les
{0,1}:n
relations en général, ou - comme vous l'avez écrit - que c'est la "bonne façon". Utilisez des optimisations comme celle-ci qui ne compliqueront vos programmes que lorsque vous en aurez vraiment besoin.la source
Le modèle conceptuel ressemblera à ceci, ce qui est pour le moins très peu orthodoxe :
Le modèle physique ressemblera à ceci, ce qui est déroutant pour le moins (les gens penseront que c'est M: M à moins qu'ils ne voient de près):
Ma suggestion:
Si vous avez comme, de nombreuses colonnes (FK ou autre), qui ne s'appliquent pas à la plupart des étudiants, séparez les tables en tables de rôle avec des rouleaux 1: 1. Mais ce n'est pas parce qu'ils sont FK, c'est parce que les colonnes ne s'appliquent pas à la plupart des lignes.
Sinon , les FK annulables font normalement partie d'une base de données et les tables de jointure sont généralement destinées aux rouleaux M: M.
Les rôles 1: 1 sont généralement utilisés pour les tables de rôle ayant des colonnes qui s'appliquent uniquement si l'entité est d'un certain type et pour l'extraction de colonnes BLOB pour des considérations de performances ou de stockage. Avoder des valeurs nulles dans les FK n'est pas une utilisation courante pour cela.
la source
En plus d'autres réponses, je voudrais souligner qu'une valeur nulle pour la clé étrangère est ambiguë. Est-ce que ça veut dire que:
1) L'école de l'élève (le cas échéant) est inconnue (il s'agit de la signification standard de «nul» - la valeur est inconnue)
2) On sait si l’élève a ou non une école, et il n’en a pas.
Si vous utilisez la signification standard de null, comment représenteriez-vous «l'élève n'a pas d'école» dans votre modèle de clé étrangère. Dans ce cas, vous devrez probablement créer une entrée "pas d'école", avec son propre identifiant dans la table de l'école. (Pas idéal)
la source
NULL
, cela peut signifier: 1) Valeur inconnue. 2) Valeur indisponible ou retenue. 3) Attribut non applicable (je pense que cette interprétation signifie que vous pouvez spécifier unNULL
pour une clé étrangère).Les tables de base de données ont cette belle chose appelée contraintes. Il est donc très facile de faire dans la table d'intersection qui permet à seulement 1 de chaque élève d'apparaître dans la table mais de nombreuses écoles dans cette table. Vous donnant efficacement un
La théorie est agréable mais à la fin vous allez modéliser votre base de données après les questions que vous posez.
Si vous voulez poser des questions souvent avec la question: "quels élèves sont dans mon école" voulez-vous vraiment interroger la table entière des élèves ou avoir une table d'intersection facile.
Dans les bases de données: optimisez pour les questions que vous posez.
la source
Il existe un cas d'utilisation où l'utilisation d'une troisième table peut réellement avoir un sens. L'exemple peut sembler purement hypothétique, mais j'espère qu'il illustre bien mon propos. Supposons que vous ajoutiez plus de colonnes à la
students
table et, à un moment donné, vous décidez d'appliquer l'unicité aux enregistrements via un index composite sur plusieurs colonnes. Il est très probable que vous deviez également inclure laschool_id
colonne, et ici les choses commencent à devenir désordonnées. En raison de la façon dont SQL a été conçu, en insérant plusieurs enregistrements identiques oùschool_id
estNULL
sera possible. Cela est parfaitement logique d'un point de vue technique, mais est contre-intuitif et peut conduire à des résultats inattendus. D'un autre côté, il est facile d'imposer l'unicité sur la table d'intersection.J'ai dû modéliser une telle relation "facultative" récemment, où l'exigence d'une contrainte d'unicité était due à une colonne d'horodatage. Laisser la clé étrangère nullable dans la table conduit soudainement à la possibilité d'insérer des enregistrements avec le même horodatage (supposons que c'est un enregistrement par défaut, défini sur des enregistrements qui n'ont pas encore été audités / approuvés) - et la seule issue était de supprimer colonne nullable.
Donc, comme vous pouvez le voir, c'est un cas assez spécifique, et comme d'autres l'ont noté, la plupart du temps, vous seriez parfaitement d'accord avec toutes les
NULL
valeurs. Cela dépend vraiment des exigences spécifiques de votre modèle.la source
En plus des nombreuses bonnes suggestions déjà soumises, personnellement je ne suis pas fan des clés étrangères à moins qu'elles ne soient vraiment nécessaires. Il y a d'abord la relation M: M à laquelle vous faites référence. De plus, appeler une clé étrangère, et ainsi extraire ces données de table dans vos requêtes, introduit plus de complexité et, en fonction de la taille de la table, des performances plus lentes. Comme d'autres l'ont dit, les champs FK annulables peuvent être non pris en charge et peuvent créer des problèmes d'intégrité des données.
Si vous définissez un état où l'école étudiante est inconnue ou vide, la valeur NULL ne différenciera pas ces conditions. (encore une fois, nous sommes de retour à l'intégrité des données.) La suggestion de table de rôle par Tulains est élégante et permet des valeurs nulles proprement.
la source