Va bene avere una chiave esterna come chiave primaria?


102

Ho due tavoli:

  • Utente (nome utente, password)
  • Profilo (ID profilo, sesso, data di nascita, ...)

Attualmente sto utilizzando questo approccio: ogni record di profilo ha un campo denominato "userId" come chiave esterna che si collega alla tabella Utente. Quando un utente si registra, il suo record del profilo viene creato automaticamente.

Sono confuso con il suggerimento del mio amico: avere il campo "userId" come chiave esterna e primaria ed eliminare il campo "profileId". Quale approccio è migliore?


3
Entity Framework genera quello (con il codice prima) per le relazioni zeroOrOne (e uno) -to-. Quindi ... è possibile. È il modo migliore ... Questa è un'altra domanda. Ma è valido. Non l'ho mai fatto mentre creavo i miei database (ma non ci avevo nemmeno pensato).
Raphaël Althaus,

Risposte:


132

Le chiavi esterne sono quasi sempre "Consenti duplicati", il che le renderebbe inadatte come chiavi primarie.

Invece, trova un campo che identifica in modo univoco ogni record nella tabella o aggiungi un nuovo campo (un numero intero con incremento automatico o un GUID) che funga da chiave primaria.

L'unica eccezione a questo sono le tabelle con una relazione uno a uno , in cui la chiave esterna e la chiave primaria della tabella collegata sono la stessa cosa.


73
Una chiave primaria composita composta da due chiavi esterne è perfetta anche per l'implementazione di relazioni molti a molti.
rightfold

1
@rezadru: lungi da me essere in disaccordo con rightfold, ma una chiave surrogata è quasi sempre una scelta migliore.
Robert Harvey,

4
Niente su una chiave esterna impone che sia 1 a molti (o "consenti duplicati" come scritto). I vincoli chiave e l'unicità sono due concetti separati in un database e possono essere facilmente combinati con la stessa facilità con cui si aggiunge un indice (che sarebbe un terzo concetto separato).
blindguy

40

Le chiavi primarie devono sempre essere univoche, le chiavi esterne devono consentire valori non univoci se la tabella è una relazione uno-a-molti. È perfettamente corretto utilizzare una chiave esterna come chiave primaria se la tabella è collegata da una relazione uno-a-uno, non da una relazione uno-a-molti. Se vuoi che lo stesso record utente abbia la possibilità di avere più di 1 record di profilo correlato, scegli una chiave primaria separata, altrimenti mantieni ciò che hai.


11

Sì, è legale che una chiave primaria sia una chiave esterna. Questo è un costrutto raro, ma si applica a:

  • una relazione 1: 1. Le due tabelle non possono essere unite in una a causa di autorizzazioni e privilegi diversi si applicano solo a livello di tabella (a partire dal 2017, un database di questo tipo sarebbe strano).

  • una relazione 1: 0..1. Il profilo può o non può esistere, a seconda del tipo di utente.

  • le prestazioni sono un problema e il design funge da partizione: si accede raramente alla tabella dei profili, è ospitata su un disco separato o ha una politica di partizionamento diversa rispetto alla tabella degli utenti. Non avrebbe senso se l'archiviazione della sottolineatura fosse a colonne.


Ci sarebbe una performance negativa se i tavoli venissero uniti spesso, il che porta alla normale raccomandazione che 1 tavolo è migliore. In alcuni casi si accede sempre ai dati separatamente, non uniti, e può esserci un vantaggio organizzativo nell'avere due tabelle con una relazione 1: 1.
blindguy

4

Generalmente è considerata una cattiva pratica avere una relazione uno a uno. Questo perché potresti semplicemente avere i dati rappresentati in una tabella e ottenere lo stesso risultato.

Tuttavia, in alcuni casi potresti non essere in grado di apportare queste modifiche alla tabella a cui fai riferimento. In questo caso non ci sono problemi utilizzando la chiave esterna come chiave primaria. Potrebbe essere utile disporre di una chiave composita costituita da una chiave primaria univoca con incremento automatico e dalla chiave esterna.

Attualmente sto lavorando a un sistema in cui gli utenti possono accedere e generare un codice di registrazione da utilizzare con un'app. Per motivi che non approfondirò, non sono in grado di aggiungere semplicemente le colonne richieste alla tabella degli utenti. Quindi sto percorrendo un percorso uno a uno con la tabella dei codici.


2
Sono d'accordo principalmente con te sul fatto che ci sono molti vantaggi nell'avere tutti i dati nella stessa tabella come colonne aggiuntive. Nonostante ciò .. "potresti semplicemente avere i dati rappresentati in una tabella e ottenere lo stesso risultato" ..: avere una tabella separata può essere utile, ad esempio qui se la voce della tabella del profilo è opzionale. Ad esempio, ogni cliente di banca potrebbe non disporre di una registrazione bancaria in Internet. In tal caso, la tabella di registrazione IB potrebbe essere utilizzata per impedire ad altre tabelle di avere ulteriori record figlio. Anche in questo caso, potrebbe essere fatto con un nuovo PK anche per la tabella di registrazione IB.
Teddy

1
@ Teddy Allo stesso modo sono per lo più d'accordo con quello che hai detto. Tuttavia, nella domanda originale indicano "... il suo record del profilo viene creato automaticamente ...", il che implica che la tabella del profilo non è facoltativa. In una situazione in cui la tabella dei profili era facoltativa, è possibile averla come tabella separata. Ma poi di nuovo, potrebbero semplicemente usare colonne nullable nella stessa tabella.
Tshsmith

1
Utilizzando una seconda tabella separata, possiamo impedire l'ingresso in una terza tabella che è consentita solo per le persone che hanno una voce nella seconda tabella.
Teddy

Assolutamente, ma se uniamo le tabelle 1 a 1 possiamo impedire alle persone con valori nulli di accedere alla terza tabella (tecnicamente la seconda ora). Ma la domanda posta da OP contiene la riga "... quando si iscrive ... ... il suo record di profilo viene creato automaticamente ...", rendendo questo ridondante.
Tshsmith

La ragione principale per considerare questo aspetto è che nel data warehousing è buona norma separare le tabelle dei fatti e delle dimensioni. Le tabelle separate dei fatti e delle dimensioni sono suggerimenti utili quando si lavora con software come PowerPivot, PowerBI e Tableau.
Marco Rosas

4

Sì, una chiave esterna può essere una chiave primaria nel caso di una relazione uno a uno tra quelle tabelle


2
questo è utile anche per la progettazione di supertipo-sottotipo. La chiave primaria delle tabelle dei sottotipi deve essere un riferimento di chiave esterna alla tabella dei supertipi.
axelioo

2

Non lo farei. Terrò profileIDcome chiave primaria della tabellaProfile

Una chiave esterna è solo un vincolo referenziale tra due tabelle

Si potrebbe sostenere che una chiave primaria è necessaria come destinazione di qualsiasi chiave esterna che vi fa riferimento da altre tabelle. Una chiave esterna è un insieme di una o più colonne in qualsiasi tabella (non necessariamente una chiave candidata, per non parlare della chiave primaria, di quella tabella) che può contenere i valori trovati nelle colonne della chiave primaria di alcune altro tavolo. Quindi dobbiamo avere una chiave primaria per abbinare la chiave esterna. O dobbiamo? L'unico scopo della chiave primaria nella coppia chiave primaria / chiave esterna è fornire un join univoco - per mantenere l'integrità referenziale rispetto alla tabella "esterna" che contiene la chiave primaria referenziata. Ciò assicura che il valore a cui si riferisce la chiave esterna sarà sempre valido (o nullo, se consentito).

http://www.aisintl.com/case/primary_and_foreign_key.html


1
Forse - se hai il vincolo FK tra User.UserID e Profile.UserID, allora sarebbe fortemente consigliato avere un indice su Profile.UserID. Perché non renderlo l'indice cluster primario sul profilo della tabella, salvando un secondo indice e un sacco di lavoro non necessario per il motore di database?
Ingegnere inverso

1

Dipende dall'attività e dal sistema.

Se il tuo userId è unico e sarà sempre unico, puoi utilizzare userId come chiave primaria. Ma se mai vorrai espandere il tuo sistema, renderà le cose difficili. Ti consiglio di aggiungere una chiave esterna nel profilo della tabella per creare una relazione con il profilo della tabella invece di aggiungere una chiave esterna nel profilo della tabella.


0

Risposta breve: DIPENDE .... In questo caso particolare, potrebbe andare bene. Tuttavia, gli esperti lo sconsigliano quasi ogni volta; compreso il tuo caso.

Perché?

Le chiavi sono raramente uniche nelle tabelle quando sono estranee (originate in un'altra tabella) alla tabella in questione. Ad esempio, un ID articolo potrebbe essere univoco in una tabella ITEMS, ma non in una tabella ORDERS, poiché molto probabilmente lo stesso tipo di articolo esisterà in un altro ordine. Allo stesso modo, gli ID ordine potrebbero essere univoci (potrebbero) nella tabella ORDERS, ma non in qualche altra tabella come ORDER_DETAILS in cui può esistere un ordine con più elementi pubblicitari e per eseguire query su un particolare elemento in un determinato ordine, è necessaria la concatenazione di due FK (order_id e item_id) come PK per questa tabella.

Non sono un esperto di DB, ma se puoi giustificare logicamente di avere un valore generato automaticamente come PK, lo farei. Se ciò non è pratico, una concatenazione di due (o forse più) FK potrebbe servire come PK. MA, non riesco a pensare a nessun caso in cui un singolo valore FK possa essere giustificato come PK.

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.