Svantaggi dell'utilizzo di una chiave esterna nullable invece della creazione di una tabella di intersezione


15

Supponiamo di avere il seguente diagramma ER:

inserisci qui la descrizione dell'immagine

Ora, se rappresentassi la relazione usando una chiave esterna di Schoolin Student, potrei avere dei NULLvalori (perché a Student non è richiesto di appartenere a a School), ad esempio:

inserisci qui la descrizione dell'immagine

Quindi il modo corretto (basato su ciò che ho letto) è quello di creare una tabella di intersezione per rappresentare la relazione, ad esempio:

inserisci qui la descrizione dell'immagine

In questo modo, nessun NULLvalore può essere presente nella tabella School_has_Student.

Ma quali sono gli svantaggi dell'utilizzo di una chiave esterna nullable invece di creare una tabella di intersezione?


Modificare:

Ho erroneamente scelto ( school_id, student_id) di essere la chiave primaria per la School_has_Studenttabella, che ha reso la relazione molti-a-molti. La chiave primaria corretta avrebbe dovuto essere student_id:

inserisci qui la descrizione dell'immagine


7
Non esiste un modo "corretto". C'è solo il modo migliore per le tue esigenze.
MetaFight,

1
Concordo con Doc sulla falsa premessa, ma forse è ancora abbastanza chiaro per rispondere?
MetaFight,

C'è una premessa errata, ma è abbastanza facile raddrizzare e spiegare la differenza.

Ho ritirato il mio voto ravvicinato, ma la frase "Quindi il modo corretto (basato su ciò che ho letto) è creare una tabella di intersezione per rappresentare la relazione" mi dà l'impressione che dovresti dirci quale fonte strainge ti ha detto che questa è la " modo corretto. In ogni libro di testo che ho letto prima, il modo canonico per le relazioni 1: n è una singola chiave esterna. O hai frainteso qualcosa?
Doc Brown,

@ Brown Brown Non ricordo dove l'ho letto, ma sono sicuro che dice che una tabella di intersezione era la strada corretta. Ad ogni modo, puoi darmi il nome di un libro che dice che una relazione 1: n (con partecipazione facoltativa sul lato: 1) dovrebbe essere rappresentata usando una singola chiave esterna, sono interessato a leggere quello che dicono su questo argomento.
Tom,

Risposte:


18

I due modelli rappresentano relazioni diverse.

Utilizzando una tabella di join, si modella una relazione molti-a-molti.

Usando una semplice chiave esterna, stai modellando una relazione uno-a-molti.

Lo svantaggio di una chiave esterna nullable è di non riuscire a modellare la relazione come molti-a-molti, se è quello che stai cercando di realizzare.


In base alla tua modifica alla domanda, stai effettivamente dividendo la tabella degli studenti in due tabelle con la stessa chiave. In genere lo vedo su tavoli che hanno troppi campi, quindi qualcuno li divide in due per essere più gestibili (lo chiamo mettendo il rossetto su un maiale).

Dividendo la tabella degli studenti, si rende facoltativa la seconda tabella poiché nella seconda tabella non è necessario un record. Che è molto simile a un campo che non deve essere impostato perché può essere nullo.

Se si desidera una relazione uno-a-molti, è molto meglio usare una singola tabella e consentire l'ID scuola di essere nullo nella tabella degli studenti. Non c'è motivo di evitare valori nulli nei campi, anche per una chiave esterna. Ciò significa che la relazione estera è facoltativa: gli sviluppatori e i DBA lo capiscono chiaramente e il motore di database sottostante dovrebbe sicuramente funzionare bene.

Se sei preoccupato per le iscrizioni, non preoccuparti. Esistono semantiche ben definite su come funzionano i join con i campi null. Utilizzando una singola tabella, è possibile unire due tabelle anziché tre.


Quindi, se sto modellando una relazione uno-a-molti (con partecipazione facoltativa sul lato: 1), dovrei usare una chiave esterna nonostante il fatto che possa avere NULLvalori?
Tom,

1
@Tom sì, è esattamente come modellarlo. Sebbene tecnicamente possibile utilizzare una tabella di join, il modello di dati consente a molti a molti, quindi per evitarlo sono necessari trigger e logica del database. Stai meglio limitando la relazione in modo che sia impossibile aggiungere dati errati.

1
Ho modificato la mia domanda. Ho creato solo student_iduna chiave primaria nella School_has_Studenttabella, che ha mantenuto la relazione come una-a-molte. Quali sono gli svantaggi di questo metodo rispetto all'utilizzo di una chiave esterna?
Tom,

@ Tom ho modificato la mia risposta.

6

Hai scritto in un commento sopra:

il libro "Fondamenti di sistemi di database" [...] afferma che si consiglia di utilizzare una tabella di intersezione se nella colonna chiave esterna sono presenti molti valori NULL (ad esempio: se il 98% dei dipendenti non gestire un dipartimento)

Quando ci sono molti valori NULL nella colonna chiave esterna, i tuoi programmi dovranno occuparsi di questa colonna per lo più vuota per ogni record che elaborano. La colonna occuperà probabilmente un po 'di spazio su disco anche se nel 98% dei casi è vuota, interrogare la relazione significa interrogare quella colonna che ti dà più traffico di rete e se stai usando un ORM che genera le classi dalle tue tabelle, i tuoi programmi avrà anche bisogno di più spazio sul lato client del necessario. L'uso di una tabella di intersezione evita questo, ci saranno solo i record di link necessari dove altrimenti la chiave esterna equivalente non sarebbe NULL.

Al contrario, se non hai solo pochi valori NULL, diciamo che il 50% o più relazioni non sono NULL, l'uso di una tabella di intersezione ti dà l'effetto opposto: più spazio su disco, maggiore complessità con conseguente più traffico di rete ecc.

Quindi utilizzare una tabella di intersezione è solo una forma di ottimizzazione, sensata solo per un caso specifico, e soprattutto al giorno d'oggi, in cui lo spazio su disco e la memoria sono diventati più economici, molto meno frequentemente necessari. Si noti che "Fondamenti dei sistemi di database" è stato originariamente scritto più di 20 anni fa (ho trovato un riferimento alla seconda edizione del 1994) e immagino che la raccomandazione fosse già lì in quel momento. Prima del 1994, l'ottimizzazione dello spazio era probabilmente molto più importante di oggi, poiché l'archiviazione di massa era ancora più costosa e i computer e le reti erano molto più lenti di oggi.

Come nota a margine di un commento schizzinoso: la precedente affermazione sta solo cercando di anticipare ciò che l'autore di "Fundamentals of Database Systems" aveva in mente con la sua raccomandazione, immagino che stesse facendo una dichiarazione generale approssimativa, valida per la maggior parte dei sistemi. In alcuni database ci sono altre possibili ottimizzazioni come "colonne sparse" che rendono ancora più obsoleto l'uso di una tabella di intersezione.

Quindi non fraintendere quella raccomandazione. Il libro non ti dice di preferire le tabelle di intersezione per le {0,1}:nrelazioni in generale, o - come hai scritto - che questo è il "modo corretto". Usa ottimizzazioni come questa che renderanno i tuoi programmi più complicati solo quando ne avrai davvero bisogno.


Stai assumendo molto sull'implementazione del database, soprattutto considerando che l'OP non ne ha menzionato uno specifico. È più che probabile che il database sia abbastanza intelligente da utilizzare solo una piccola quantità di spazio per le colonne sparse.
gardenhead

@gardenhead: cosa ti fa credere che questo sia "più che probabile"?
Doc Brown,

Il fatto che i database esistano da decenni e siano altamente ottimizzati in quanto sono una componente critica della maggior parte delle infrastrutture.
gardenhead

@gardenhead: mi sembra che tu stia formulando ipotesi ingiustificate su di me. Tuttavia, vedi la mia modifica.
Doc Brown,

2

Il modello concettuale sarà simile a questo, il che è molto poco ortodosso per non dire altro:

inserisci qui la descrizione dell'immagine

Il modello fisico sarà simile a questo, il che è confuso a dir poco (le persone penseranno che sia M: M a meno che non vedano da vicino):

inserisci qui la descrizione dell'immagine

Il mio consiglio:

Se ne hai, molte colonne (FK o altro), che non si applicano alla maggior parte degli studenti, separano le tabelle in tabelle dei ruoli con rel 1: 1. Ma non è perché sono FK, è perché le colonne non si applicano alla maggior parte delle righe.

Altrimenti , l' FK nullable è una parte normale di un database e le tabelle di join sono in genere per M: M rels.

Gli usi comuni delle rel 1: 1 sono per le tabelle dei ruoli con colonne applicabili solo se l'entità è di un certo tipo ed estrazione delle colonne BLOB per considerazioni su prestazioni o archiviazione. Avodificare i valori null negli FK non è un uso comune per questo.

inserisci qui la descrizione dell'immagine


2

Oltre ad altre risposte, vorrei sottolineare che un valore nullo per la chiave esterna è ambiguo. Significa:

1) La scuola dello studente (se presente) è sconosciuta (questo è il significato standard di 'null' - il valore è sconosciuto)

2) È noto se lo studente ha o meno una scuola e non ne hanno

Se usi il significato standard di null, come rappresenteresti "studente non ha scuola" nel tuo modello di chiave straniera. In tal caso, probabilmente dovresti creare una voce "nessuna scuola", con il suo ID nel tavolo della scuola. (Non ideale)


2
Il libro "Fondamenti di sistemi di database" menziona che ci sono 3 interpretazioni per NULL, può significare: 1) Valore sconosciuto. 2) Valore non disponibile o trattenuto. 3) Attributo non applicabile (penso che questa interpretazione significhi che è possibile specificare un NULLper una chiave esterna).
Tom,

1
È un elenco utile, ma la semantica di null (o qualsiasi valore in realtà) è definibile dall'utente. Cioè può significare qualunque cosa il designer dice che significa, non limitato a quell'elenco. Il problema è come distinguere significati diversi quando potrebbe essere necessario più di uno (o addirittura salvato involontariamente)
Brad Thomas

Quindi stai suggerendo che dovrei creare una tabella di intersezione invece di utilizzare una chiave esterna nullable?
Tom,

@Tom Sì, credo che sia meglio in questo caso
Brad Thomas,

@BradThomas - per evitare la stessa ambiguità quando si utilizza una tabella di intersezione, rappresenteresti il ​​caso 2 (è noto che lo studente non ha scuola) da un record nella tabella di intersezione con un NULL School_ID?
Andrew

1

Le tabelle del database hanno questa bella cosa chiamata vincoli. Quindi è molto facile creare nella tabella di intersezione che consente a solo 1 di ogni studente di apparire nella tabella ma molte scuole in quella tabella. Dandoti efficacemente a

La teoria è buona ma alla fine modellerai il tuo database dopo le domande che stai ponendo.

Se vuoi fare spesso domande con la domanda: "quali studenti sono nella mia scuola", vuoi davvero interrogare l'intera tabella degli studenti o avere una tabella di intersezione semplice.

Nei database: ottimizza per le domande che fai.


0

Esiste un caso d'uso in cui l'utilizzo di una terza tabella può effettivamente avere senso. L'esempio può sembrare puramente ipotetico, ma spero che illustri bene il mio punto. Supponiamo che tu aggiunga più colonne alla studentstabella e ad un certo punto, decidi di applicare l'univocità sui record tramite l'indice composito su più colonne. È molto probabile che dovrai includere anche la school_idcolonna e qui le cose iniziano a diventare confuse. A causa del modo SQL creata, inserendo diversi dischi identici dove school_idè NULLsarà possibile. Ha perfettamente senso dal punto di vista tecnico, ma è controintuitivo e può portare a risultati inaspettati. D'altra parte, far rispettare l'unicità sul tavolo di intersezione è facile.

Di recente ho dovuto modellare una relazione "facoltativa", in cui il requisito per un vincolo di unicità era dovuto a una colonna timestamp. Lasciare la chiave esterna nullable nella tabella porta all'improvviso alla possibilità di inserire record con lo stesso timestamp (supponiamo che sia predefinito, impostato su record che non sono stati ancora controllati / approvati) - e l'unica via d'uscita era rimuovere colonna nullable.

Come puoi vedere, è un caso abbastanza specifico, e come altri hanno notato, la maggior parte delle volte saresti perfettamente a posto con tutti i NULLvalori. Dipende davvero dai requisiti specifici del tuo modello.


0

Oltre ai tanti buoni suggerimenti già presentati, personalmente non sono un fan delle chiavi esterne a meno che non siano veramente necessarie. Innanzitutto c'è la relazione M: M a cui stai facendo riferimento. Inoltre, la chiamata di una chiave esterna e quindi l'inserimento di tali dati nelle query, introduce maggiore complessità e, a seconda delle dimensioni della tabella, prestazioni più lente. Come altri hanno già detto, i campi FK nullable possono essere non supportati e possono creare problemi di integrità dei dati.

Se si sta definendo uno stato in cui la scuola studentesca è sconosciuta o vuota, il NULL non differenzierà tali condizioni. (di nuovo torniamo all'integrità dei dati.) Il suggerimento della tabella dei ruoli di Tulains è elegante e consente valori nulli in modo pulito.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.