Inconvénients de l'utilisation d'une clé étrangère nullable au lieu de créer une table d'intersection


15

Disons que j'ai le diagramme ER suivant:

entrez la description de l'image ici

Maintenant, si je représentais la relation à l'aide d'une clé étrangère de Schoolin Student, je pourrais avoir des NULLvaleurs (car il Student n'est pas nécessaire que a appartienne à a School), par exemple:

entrez la description de l'image ici

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:

entrez la description de l'image ici

De cette façon, aucune NULLvaleur 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_Studenttable, ce qui a rendu la relation plusieurs à plusieurs. La clé primaire correcte aurait dû être student_id:

entrez la description de l'image ici


7
Il n'y a aucun moyen "correct". Il y a juste la meilleure façon de répondre à vos besoins.
MetaFight

1
Je suis d'accord avec Doc au sujet de la fausse prémisse, mais peut-être qu'elle est encore suffisamment claire pour répondre?
MetaFight

Il existe une fausse prémisse, mais il est assez facile de redresser et d'expliquer la différence.

J'ai rétracté mon vote serré, mais la phrase "Donc, la bonne façon (sur la base de ce que j'ai lu) est de créer une table d'intersection pour représenter la relation" me donne l'impression que vous devriez nous dire quelle source strainge vous a dit que c'était la " correcte ". Dans tous les manuels que j'ai lus auparavant, la manière canonique pour les relations 1: n est une seule clé étrangère. Ou avez-vous mal compris quelque chose?
Doc Brown

@Doc Brown Je ne me souviens pas où je l'ai lu, mais je suis sûr qu'il dit qu'une table d'intersection était la bonne façon. Quoi qu'il en soit, pouvez-vous me donner le nom d'un livre qui dit qu'une relation 1: n (avec participation facultative du côté: 1) devrait être représentée à l'aide d'une seule clé étrangère, je suis intéressé à lire ce qu'ils disent à ce sujet.
Tom

Réponses:


18

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.


Donc, si je modélise une relation un-à-plusieurs (avec participation facultative du côté: 1), dois-je utiliser une clé étrangère malgré le fait qu'elle puisse avoir des NULLvaleurs?
Tom

1
@ Tom oui, c'est exactement comment le modéliser. Bien qu'il soit techniquement possible d'utiliser une table de jointure, le modèle de données permet plusieurs à plusieurs, vous aurez donc besoin de déclencheurs et d'une logique de base de données pour éviter cela. Vous êtes mieux en restreignant la relation de manière à ce qu'il soit impossible d'ajouter des données incorrectes.

1
J'ai modifié ma question. Je n'ai créé student_idqu'une clé primaire dans le School_has_Studenttableau, 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?
Tom

@Tom j'ai édité ma réponse.

6

Vous avez écrit dans un commentaire ci-dessus:

le livre "Fundamentals of Database Systems" dit [...] qu'il est recommandé d'utiliser une table d'intersection s'il y a beaucoup de valeurs NULL dans la colonne de clé étrangère (par exemple: si 98% des employés ne gère pas de département)

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}:nrelations 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.


Vous supposez beaucoup sur la mise en œuvre de la base de données, d'autant plus que l'OP n'en a pas mentionné de spécifique. Il est plus que probable que la base de données est suffisamment intelligente pour n'utiliser qu'une petite quantité d'espace pour les colonnes éparses.
gardenhead

@gardenhead: qu'est-ce qui vous fait croire que c'est "plus que probable"?
Doc Brown

Le fait que les bases de données existent depuis des décennies et sont hautement optimisées car elles sont un composant essentiel de la plupart des infrastructures.
gardenhead

@gardenhead: il me semble que vous faites beaucoup plus d'hypothèses injustifiées que moi. Néanmoins, voir mon montage.
Doc Brown

2

Le modèle conceptuel ressemblera à ceci, ce qui est pour le moins très peu orthodoxe :

entrez la description de l'image ici

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):

entrez la description de l'image ici

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.

entrez la description de l'image ici


2

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)


2
Le livre "Fundamentals of Database Systems" mentionne qu'il y a 3 interprétations pour 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 un NULLpour une clé étrangère).
Tom

1
C'est une liste utile mais la sémantique de null (ou n'importe quelle valeur vraiment) peut être définie par l'utilisateur. C'est-à-dire que cela peut signifier tout ce que le concepteur dit, cela ne se limite pas à cette liste. Le problème est de savoir comment distinguer différentes significations lorsque plusieurs peuvent être nécessaires (ou même enregistrées involontairement)
Brad Thomas

Suggérez-vous donc que je devrais créer une table d'intersection au lieu d'utiliser une clé étrangère nullable?
Tom

@ Tom Oui, je pense que c'est mieux dans ce cas
Brad Thomas

@BradThomas - pour éviter la même ambiguïté lors de l'utilisation d'une table d'intersection, représenteriez-vous le cas 2 (il est connu que l'élève n'a pas d'école) par un enregistrement dans la table d'intersection avec un NULL School_ID?
andrew

1

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.


0

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 studentstable 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 la school_idcolonne, 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_idest NULLsera 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 NULLvaleurs. Cela dépend vraiment des exigences spécifiques de votre modèle.


0

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.