Domanda

Esiste un sano dibattito tra surrogato e chiavi naturali:

SO Post 1

SO Post 2

La mia opinione, che sembra essere in linea con la maggioranza (è una maggioranza sottile), è che dovresti usare le chiavi surrogate a meno che una chiave naturale sia completamente ovvia e garantisca di non cambiare. Quindi dovresti applicare l'unicità sulla chiave naturale. Il che significa chiavi surrogate quasi sempre.

Esempio dei due approcci, a partire da una tabella aziendale:

1: chiave surrogata: la tabella ha un campo ID che è il PK (e un'identità). I nomi delle società devono essere univoci per stato, quindi esiste un vincolo univoco lì.

2: Chiave naturale: la tabella utilizza CompanyName e State come PK - soddisfa sia la PK sia l'unicità.

Supponiamo che la società PK sia utilizzata in altre 10 tabelle. La mia ipotesi, senza numeri per sostenerlo, è che l'approccio chiave surrogato sarebbe molto più veloce qui.

L'unico argomento convincente che ho visto per la chiave naturale è per molte o molte tabelle che usano le due chiavi esterne come chiave naturale. Penso che in quel caso abbia senso. Ma puoi metterti nei guai se hai bisogno di refactoring; penso che sia fuori dallo scopo di questo post.

Qualcuno ha visto un articolo che confronta le differenze di rendimento su un set di tabelle che usano chiavi surrogate vs. lo stesso set di tabelle usando chiavi naturali ? Guardarsi intorno su SO e Google non ha prodotto nulla di utile, solo un sacco di teorie.


Aggiornamento importante : ho iniziato a creare un set di tabelle di test che rispondono a questa domanda. Sembra così:

  • PartNatural - tabella delle parti che utilizza il PartNumber univoco come PK
  • PartSurrogate - tabella delle parti che utilizza un ID (int, identità) come PK e ha un indice univoco su PartNumber
  • Impianto - ID (int, identità) come PK
  • Ingegnere - ID (int, identità) come PK

Ogni parte è unita a un impianto e ogni istanza di una parte in un impianto è unita a un ingegnere. Se qualcuno ha un problema con questo banco di prova, ora è il momento.

È stato utile?

Soluzione

Usa entrambi! Le chiavi naturali impediscono il danneggiamento del database (incoerenza potrebbe essere una parola migliore). Quando il "giusto" la chiave naturale (per eliminare le righe duplicate) funzionerebbe male a causa della lunghezza o del numero di colonne coinvolte, ai fini delle prestazioni, è possibile aggiungere una chiave surrogata e usarla come chiavi esterne in altre tabelle anziché la chiave naturale. Ma la chiave naturale dovrebbe rimanere come chiave alternativa o indice univoco per prevenire il danneggiamento dei dati e rafforzare la coerenza del database ...

Gran parte dell'hoohah (nel "dibattito" su questo tema), potrebbe essere dovuto a ciò che è un falso presupposto - che devi usare la Chiave primaria per join e chiavi esterne in altre tabelle. QUESTO È FALSO. Puoi utilizzare QUALSIASI chiave come destinazione per le chiavi esterne in altre tabelle. Può essere la chiave primaria, una chiave alternativa o qualsiasi indice univoco o vincolo univoco. E per quanto riguarda i join, puoi usare qualsiasi cosa per una condizione di join, non deve nemmeno essere una chiave, un idex o persino unico !! (anche se se non è univoco otterrai più righe nel prodotto cartesiano che crea).

Altri suggerimenti

Le chiavi naturali differiscono dalle chiavi surrogate per valore, non per tipo.

Qualsiasi tipo può essere usato per una chiave surrogata, come un VARCHAR per il slug generato dal sistema o qualcos'altro.

Tuttavia, i tipi più utilizzati per le chiavi surrogate sono INTEGER e RAW (16) (o qualunque tipo di RDBMS usi per GUID 's),

Il confronto di numeri interi surrogati e numeri interi naturali (come SSN ) richiede esattamente lo stesso tempo.

Il confronto tra VARCHAR tiene conto delle regole di confronto e sono generalmente più lunghe degli interi, il che le rende meno efficienti.

Il confronto di una serie di due INTEGER è probabilmente anche meno efficiente rispetto al confronto di un singolo INTEGER .

Su tipi di dati di dimensioni ridotte questa differenza è probabilmente percentuali di percentuali del tempo necessario per recuperare pagine, attraversare indici, acquisire blocchi di database ecc.

Ed ecco i numeri (in MySQL ):

CREATE TABLE aint (id INT NOT NULL PRIMARY KEY, value VARCHAR(100));
CREATE TABLE adouble (id1 INT NOT NULL, id2 INT NOT NULL, value VARCHAR(100), PRIMARY KEY (id1, id2));
CREATE TABLE bint (id INT NOT NULL PRIMARY KEY, aid INT NOT NULL);
CREATE TABLE bdouble (id INT NOT NULL PRIMARY KEY, aid1 INT NOT NULL, aid2 INT NOT NULL);

INSERT
INTO    aint
SELECT  id, RPAD('', FLOOR(RAND(20090804) * 100), '*')
FROM    t_source;

INSERT
INTO    bint
SELECT  id, id
FROM    aint;

INSERT
INTO    adouble
SELECT  id, id, value
FROM    aint;

INSERT
INTO    bdouble
SELECT  id, id, id
FROM    aint;

SELECT  SUM(LENGTH(value))
FROM    bint b
JOIN    aint a
ON      a.id = b.aid;

SELECT  SUM(LENGTH(value))
FROM    bdouble b
JOIN    adouble a
ON      (a.id1, a.id2) = (b.aid1, b.aid2);

t_source è solo una tabella fittizia con 1.000.000 righe

aint e adouble , bint e bdouble contengono esattamente gli stessi dati, tranne che non è ha un numero intero come PRIMARY KEY , mentre adouble ha una coppia di due numeri interi identici.

Sul mio computer, entrambe le query vengono eseguite per 14,5 secondi, +/- 0,1 secondi

L'eventuale differenza di prestazioni rientra nell'intervallo delle fluttuazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top