chiavi primarie composite è una cattiva pratica? [chiuso]


14

Voglio sapere se le chiavi primarie composite sono una cattiva pratica e, in caso contrario, su quali scenari è consigliabile utilizzare.

La mia domanda si basa su questo articolo

errori di progettazione dei database

La parte relativa alle chiavi primarie composite:

Cattiva pratica n. 6: chiavi primarie composite

Questo è una specie di punto controverso, dal momento che molti progettisti di database parlano oggigiorno dell'utilizzo di un campo generato automaticamente dall'ID intero come chiave primaria anziché di uno composito definito dalla combinazione di due o più campi. Questa è attualmente definita come la "migliore pratica" e, personalmente, tendo ad accettarla.

Immagine di una chiave primaria composita

Tuttavia, questa è solo una convenzione e, naturalmente, i DBE consentono la definizione di chiavi primarie composite, che molti designer ritengono inevitabili. Pertanto, come per la ridondanza, le chiavi primarie composite sono una decisione di progettazione.

Attenzione, tuttavia, se si prevede che la tabella con una chiave primaria composita abbia milioni di righe, l'indice che controlla la chiave composita può crescere fino a un punto in cui le prestazioni dell'operazione CRUD sono molto ridotte. In tal caso, è molto meglio utilizzare una chiave primaria ID intero semplice il cui indice sarà sufficientemente compatto e stabilire i vincoli DBE necessari per mantenere l'univocità.


4
Questa non è una pratica "buona" o "cattiva". Ogni decisione di progettazione deve avere uno scopo; se riesci a spiegare (a te stesso e agli altri) perché hai bisogno di un PK composito, sei a posto. Al contrario, se riesci a spiegare perché non ne hai bisogno, anche tu puoi andare. A mio avviso, l'articolo a cui ti colleghi fa un pessimo lavoro di spiegazione.
Mustaccio,

questo articolo segnala un punto, ma se guardiamo i framework popolari (come ad esempio le rotaie) nelle sue "best practice" non supportano questo tipo di chiavi primarie, quindi ho chiesto perché? è per difficoltà tecniche o qualcos'altro.
hackvan,

Per i progetti di framework è più semplice supportare solo chiavi primarie intere a colonna singola "semplici". E poiché la maggior parte degli sviluppatori (almeno nella mia esperienza personale) non ha molto in termini di capacità di database (almeno relativamente agli utenti di questo sito), funziona abbastanza bene per la maggior parte degli utenti del software. Poiché la maggior parte degli utenti del software non ha bisogno di chiavi composite (o non pensa di averne bisogno, almeno all'inizio), può cavarsela senza fornire (buono) supporto per chiavi composite.
Willem Renzema,

1
In che modo un GUID è meglio di un INTEGER [Seriale | Auto_Increment | Identità | <whatever_integer_you_like>]?
Vérace,

4
Non assumerei
quell'autore

Risposte:


31

Dire che l'uso di "Composite keys as PRIMARY KEY is bad practice"è una totale assurdità!

I compositi PRIMARY KEYsono spesso una "cosa buona" e l'unico modo per modellare situazioni naturali che si verificano nella vita di tutti i giorni!

Pensa al classico esempio di database di Database-101 di studenti e corsi e ai numerosi corsi seguiti da molti studenti!

Crea corso tavoli e studente:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Ti darò l'esempio nel dialetto PostgreSQL (e MySQL ) - dovrebbe funzionare per qualsiasi server con un po 'di modifiche.

Ora, ovviamente, vuoi tenere traccia di quale studente sta seguendo quale corso - quindi hai quello che viene chiamato un joining table(anche chiamato linking, many-to-manyo m-to-ntabelle). Sono anche conosciuti come associative entitiesin gergo tecnico!

1 corso può avere molti studenti.
1 studente può seguire molti corsi.

Quindi, si crea una tabella di unione

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Ora, l' unico modo per dare ragionevolmente a questo tavolo PRIMARY KEYè quello di creare KEYuna combinazione di corso e studente. In questo modo, non puoi ottenere:

  • un duplicato della combinazione studente e corso

    • un corso può avere lo stesso studente iscritto una sola volta e

    • uno studente può iscriversi allo stesso corso solo una volta

  • hai anche una ricerca pronta KEYper corso per studente - AKA un indice di copertura ,

  • è banale trovare corsi senza studenti e studenti che non seguono corsi!

    - L' esempio db-fiddle ha il vincolo PK ripiegato nella CREATE TABLE - Può essere fatto in entrambi i modi. Preferisco avere tutto nell'istruzione CREATE TABLE.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Ora, potresti scoprire che se le ricerche degli studenti per corso erano lente, usa a UNIQUE INDEXon (sc_student_id, sc_course_id).

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

Non v'è alcuna pallottola d'argento per l'aggiunta di indici - che saranno rendere INSERTs e UPDATEs più lento, ma al grande vantaggio di enorme decrescentiSELECT volte! Spetta allo sviluppatore decidere di indicizzare in base alle proprie conoscenze ed esperienze, ma dire che i compositi PRIMARY KEYsono sempre cattivi è semplicemente sbagliato.

Nel caso di unirsi ai tavoli, di solito sono gli unici PRIMARY KEY che hanno senso! Partecipare ai tavoli è anche molto spesso l'unico modo di modellare ciò che accade nel mondo degli affari o della natura o praticamente in ogni ambito a cui riesco a pensare!

Questo PK è anche covering indexutile per accelerare le ricerche. In questo caso, sarebbe particolarmente utile se si cercasse regolarmente (course_id, student_id) che, si potrebbe immaginare, spesso può essere il caso!

Questo è solo un piccolo esempio di dove un composito PRIMARY KEYpuò essere un'ottima idea e l'unico modo sano per modellare la realtà! In cima alla mia testa, posso pensare a molti altri.

Un esempio dal mio stesso lavoro!

Prendi in considerazione una tabella di volo contenente un flight_id, un elenco di aeroporti di partenza e di arrivo e gli orari pertinenti e quindi anche una tabella di cabine con i membri dell'equipaggio!

L' unico modo sano per modellare questo è di avere una tabella flight_crew con flight_id e crew_id come attibutes e l'unico modo sano PRIMARY KEYè usare la chiave composita dei due campi!


2
nell'esempio del corso e degli studenti, è possibile che course_student abbia una idchiave primaria e un indice univoco attivi cs_student_id cs_course_ide abbia gli stessi risultati?
hackvan,

2
Perché sprecare risorse per farlo? Con PK (course_id, student_id), per definizione hai già un indice univoco su quei campi! Un indice univoco su (student_id, course_id) potrebbe essere utile per accelerare le ricerche. Ad esempio, se stavi cercando studenti che non stavano seguendo alcun corso, ma quella decisione potrebbe essere operativa, ma in questi giorni di archiviazione relativamente economica, Lo consiglierei, soprattutto perché si potrebbe pensare che la tabella non verrà aggiornata molto frequentemente.
Vérace,

1
Accetto completamente per le tabelle dei collegamenti - sto lavorando con diversi in questo momento. Tuttavia, quando indosso il mio cappello C #, sto lavorando con il generatore di reversepoco e costruendo classi utili (trova, salva ecc.) Per il livello successivo. Ho riscontrato un grosso problema: le chiavi composite diventano una PITA per avere qualsiasi codice generico di salvataggio / ricerca. Sì, forse potrei tornare ai file EDMX ma ho ancora bisogno di aggirare il codice del caso speciale (contare le colonne Pkey?) O aggiungere una chiave surrogata artificiale (non mi piace e ho bisogno di ulteriori vincoli di unicità :(). Quindi, immagino le persone che non amano i compositi parlano dal codice del livello App.
Richard Griffiths,

A seconda della frequenza degli inserti e della frequenza di deframmentazione dell'indice rispetto alla finestra di manutenzione, questa è la soluzione migliore. Ma alcune scelte progettuali sono compromessi determinati da requisiti che potrebbero non essere immediatamente visibili. Ma come ha detto un commento, identifica i pro / contro di entrambi gli scenari e fai una scelta progettuale.
Jonathan Fite,

Cosa succede quando uno studente ripete il corso? Quindi, a meno che i corsi separati nel tempo non ottengano ID diversi, allora hai ancora un'altra tabella di mappatura. Oppure aggiungi un campo per la data del corso che ora deve essere aggiunto alla chiave.
iheanyi,

3

La mia opinione semi istruita: una "chiave primaria" non deve essere l'unica chiave univoca utilizzata per cercare i dati nella tabella, sebbene gli strumenti di gestione dei dati li offriranno come selezione predefinita. Quindi, per scegliere se avere un composto di due colonne o un numero generato casualmente (probabilmente in serie) come chiave della tabella, puoi avere due chiavi diverse contemporaneamente.

Se i valori dei dati includono un termine univoco adatto che può rappresentare la riga, preferirei dichiararlo come "chiave primaria", anche se composito, piuttosto che utilizzare una chiave "sintetica". La chiave sintetica potrebbe funzionare meglio per motivi tecnici, ma la mia scelta predefinita è quella di designare e utilizzare il termine reale come chiave primaria, a meno che non sia necessario procedere diversamente per far funzionare il servizio.

Un Microsoft SQL Server ha la caratteristica distinta ma correlata dell '"indice cluster" che controlla l'archiviazione fisica dei dati in ordine di indice e viene utilizzata anche all'interno di altri indici. Per impostazione predefinita, viene creata una chiave primaria come indice cluster, ma è possibile scegliere invece non cluster, preferibilmente dopo aver creato l'indice cluster. Quindi puoi avere una colonna di identità generata come indice cluster e, per esempio, il nome del file nvarchar (128 caratteri) come chiave primaria. Questo potrebbe essere migliore perché la chiave di indice cluster è stretta, anche se il nome del file viene archiviato come termine della chiave esterna in altre tabelle, anche se questo esempio è un buon caso per non farlo.

Se il tuo progetto prevede l'importazione di tabelle di dati che includono una chiave primaria scomoda per identificare i dati correlati, allora sei praticamente bloccato con quello.

https://www.techopedia.com/definition/5547/primary-key descrive un esempio di scelta se archiviare i dati con il numero di previdenza sociale di un cliente come chiave cliente in tutte le tabelle di dati o generare un customer_id arbitrario quando si registrali. In realtà, si tratta di un grave abuso di SSN, a prescindere dal fatto che funzioni o meno; è un valore di dati personali e confidenziali.

Quindi, un vantaggio dell'utilizzo di un fatto reale come chiave è che senza ricollegarsi alla tabella "Clienti", è possibile recuperare informazioni su di essi in altre tabelle, ma è anche un problema di sicurezza dei dati.

Inoltre, hai problemi se l'SSN o altra chiave di dati sono stati registrati in modo errato, quindi hai il valore errato in 20 tabelle vincolate anziché solo in "Cliente". Considerando che il customer_id sintetico non ha un significato esterno, quindi non può essere un valore errato.


1
Apprezzo in particolare l'osservazione secondo cui, in base ai dati dei clienti come chiave, anche i dati sui clienti unici noti (qui, SSN), si interrompono se tali dati devono essere corretti.
ToolmakerSteve
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.