Chiave primaria o indice univoco?


127

Al lavoro abbiamo un grande database con indici univoci invece di chiavi primarie e tutto funziona bene.

Sto progettando un nuovo database per un nuovo progetto e ho un dilemma:

Nella teoria del DB, la chiave primaria è l'elemento fondamentale, va bene, ma nei progetti REAL quali sono i vantaggi e gli svantaggi di entrambi?

Cosa usi nei progetti?

EDIT: ... e le chiavi primarie e la replica sul server MS SQL?


2
Ci sono alcune considerazioni aggiuntive discusse qui (anche se con il contesto aggiuntivo di un indice di copertura) - dba.stackexchange.com/questions/21554/…
StuartLC

NOTA: SQLite è diverso in quanto consente alla chiave primaria di essere nulla, rispetto allo standard comune a causa di un problema legacy. sqlite.org/lang_createtable.html
bitinn,

Risposte:


168

Che cos'è un indice univoco?

Un indice univoco su una colonna è un indice su quella colonna che impone anche il vincolo che non è possibile avere due valori uguali in quella colonna in due righe diverse. Esempio:

CREATE TABLE table1 (foo int, bar int);
CREA UNICO INDICE ux_table1_foo ON table1 (foo); - Crea un indice univoco su foo.

INSERIRE nella tabella1 (foo, bar) VALORI (1, 2); -- OK
INSERIRE nella tabella1 (foo, bar) VALORI (2, 2); -- OK
INSERIRE nella tabella1 (foo, bar) VALORI (3, 1); -- OK
INSERIRE nella tabella 1 (foo, bar) VALORI (1, 4); -- Non riesce!

Voce duplicata '1' per chiave 'ux_table1_foo'

L'ultimo inserimento non riesce perché viola l'indice univoco sulla colonna fooquando tenta di inserire il valore 1 in questa colonna per la seconda volta.

In MySQL un vincolo univoco consente NULL multipli.

È possibile creare un indice univoco su colonne multiple.

Chiave primaria contro indice univoco

Cose uguali:

  • Una chiave primaria implica un indice univoco.

Cose diverse:

  • Una chiave primaria implica anche NOT NULL, ma un indice univoco può essere nullable.
  • Può esserci solo una chiave primaria, ma possono esserci più indici univoci.
  • Se non è stato definito alcun indice cluster, la chiave primaria sarà l'indice cluster.

4
Si noti che un indice univoco è un indice su una colonna non è del tutto accurato poiché un indice univoco o chiave primaria può includere più di una colonna.
Alex Jasmin,

2
@Alexandre Jasmin: risolto grazie. La parte relativa a più colonne è menzionata più avanti.
Mark Byers,

Con riferimento ai null, gli standard ansi consentono più valori null in un set di dati con un vincolo univoco su di esso, e questa è anche l'implementazione su Oracle e PostgreSQL. Credo che SQL Server consenta tuttavia solo un valore null.
David Aldridge,

3
ma ancora non l'ho capito, come quando usare la chiave primaria o quando usare un indice univoco? o possono essere entrambi nelle stesse situazioni.
Entro il

33

Puoi vederlo così:

Una chiave primaria è unica

Un valore univoco non deve essere la rappresentazione dell'elemento

Senso?; Bene, una chiave primaria viene utilizzata per identificare l'elemento, se hai una "Persona" ti piacerebbe avere un Numero di identificazione personale (SSN o simile) che è Principale per la tua Persona.

D'altra parte, la persona potrebbe avere un'e-mail unica, ma che non identifica la persona.

Ho sempre le chiavi primarie, anche nelle tabelle delle relazioni (tabella intermedia / tabella delle connessioni) potrei averle. Perché? Beh, mi piace seguire uno standard durante la codifica, se la "Persona" ha un identificatore, la Macchina ha un identificatore, beh, allora anche la Persona -> Macchina dovrebbe avere un identificatore!


Nelle tabelle delle relazioni: intendi introdurre una nuova colonna con una chiave primaria artificiale (ad esempio un numero intero) o usi una chiave primaria composta (person_id, car_id)?

3
la chiave primaria (person_id, car_id) sarebbe la migliore. Ma in genere creo una nuova colonna, certo che dà un certo sovraccarico, ma ho ammesso che è buono. Non sai mai se vuoi relazionarti con una relazione specifica in uno scenario successivo.
Filip Ekberg,

1
L'altra cosa che la chiave primaria surrogata fa per la tabella composita / join è la facilità di manutenzione delle attività manuali.
Robert C. Barth,

2
Hai bisogno di una chiave primaria solo se hai figli. Perché aggiungere una colonna e una sequenza se il valore non appare da nessuna parte, se il valore non viene utilizzato per nulla? È un trucco per impedire ad Access di richiedere un PK. Crea un PK se devi identificare il record in un bambino, altrimenti è uno spreco.

3
Se non ha nulla a che fare con le relazioni con cosa ha a che fare? Indichi un campo e dici che è primario. E? Allora cosa succede? E se non c'è un pk naturale, aggiungo una colonna e una sequenza e un trigger e tutto perché ____? Alcuni devono solo essere primari. Evito le regole senza ragioni.

10

Le chiavi esterne funzionano con vincoli univoci e chiavi primarie. Dai libri online:

Un vincolo FOREIGN KEY non deve essere collegato solo a un vincolo PRIMARY KEY in un'altra tabella; può anche essere definito per fare riferimento alle colonne di un vincolo UNIQUE in un'altra tabella

Per la replica transazionale, è necessaria la chiave primaria. Dai libri online:

Le tabelle pubblicate per la replica transazionale devono avere una chiave primaria. Se una tabella si trova in una pubblicazione di replica transazionale, non è possibile disabilitare gli indici associati alle colonne chiave primaria. Questi indici sono richiesti dalla replica. Per disabilitare un indice, è innanzitutto necessario eliminare la tabella dalla pubblicazione.

Entrambe le risposte sono per SQL Server 2005.


CHE mi spaventa da morire (prima citazione). Perché? Ho una tabella delle persone con un ID arbitrario che è il mio PK ma decido di aggiungere un Regno Unito a telefono, e-mail e SSN ... quindi ora 4 tabelle diverse si uniscono alla persona su 4 colonne diverse? Penso che rinuncerei alla flessibilità che potresti ottenere per coerenza.

5

La scelta di quando usare una chiave primaria surrogata invece di una chiave naturale è difficile. Risposte come, sempre o mai, sono raramente utili. Trovo che dipende dalla situazione.

Ad esempio, ho le seguenti tabelle:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Abbiamo due tabelle entità ( toll_boothse cars) e una tabella transazioni ( drive_through). La toll_boothtabella utilizza una chiave surrogata perché non ha alcun attributo naturale che non è garantito cambiare (il nome può essere facilmente modificato). La carstabella utilizza una chiave primaria naturale perché ha un identificatore univoco ( vin) non modificabile . La drive_throughtabella delle transazioni utilizza una chiave surrogata per una facile identificazione, ma ha anche un vincolo univoco sugli attributi che sono garantiti come unici al momento dell'inserimento del record.

http://database-programmer.blogspot.com ha alcuni grandi articoli su questo argomento particolare.


4

Non ci sono svantaggi delle chiavi primarie.

Per aggiungere solo alcune informazioni alle risposte di @MrWiggles e @Peter Parker, quando la tabella non ha la chiave primaria, ad esempio, non sarai in grado di modificare i dati in alcune applicazioni (finiranno per dire che non è possibile modificare / eliminare i dati senza chiave primaria). Postgresql consente a più valori NULL di essere nella colonna UNIQUE, PRIMARY KEY non consente NULL. Inoltre, alcuni ORM che generano codice potrebbero presentare dei problemi con le tabelle senza chiavi primarie.

AGGIORNARE:

Per quanto ne so, non è possibile replicare le tabelle senza chiavi primarie in MSSQL, almeno senza problemi ( dettagli ).


C'è sovraccarico quando vengono inserite nuove righe o quella colonna viene aggiornata.

3

Se qualcosa è una chiave primaria, a seconda del motore DB, l'intera tabella viene ordinata in base alla chiave primaria. Questo significa che le ricerche sono molto più veloci sulla chiave primaria perché non deve fare alcuna dereferenziazione come ha a che fare con qualsiasi altro tipo di indice. Oltre a ciò, è solo teoria.


3
la tabella verrà ordinata per indice cluster non necessariamente per chiave primaria.
Ray Booysen,

1
succede solo che la maggior parte delle persone imposta la chiave primaria come indice cluster.
Ray Booysen,

Che sappiamo che è spesso una pessima idea, a meno che non ci piacciano i punti caldi e gli alberi indice sbilanciati nei nostri tavoli, ovviamente ...
Mike Woodhouse,

1
Non è SEMPRE un'idea davvero negativa. Conosci i tuoi dati, conosci il tuo RDBMS, sai cosa significano le scelte. Raramente la scelta è SEMPRE buona o cattiva. Se lo fosse SEMPRE, il database lo imporrebbe o lo proibirebbe. Ti danno la scelta perché "Dipende".

2

Oltre a quanto affermato dalle altre risposte, alcuni database e sistemi potrebbero richiedere la presenza di un elemento primario. Mi viene in mente una situazione; quando si utilizza la replica aziendale con Informix, deve essere presente un PK affinché una tabella possa partecipare alla replica.


2

Finché non si consente NULL per un valore, è necessario gestirli allo stesso modo, ma il valore NULL è gestito in modo diverso sui database (AFAIK MS-SQL non consente più di un (1) valore NULL, mySQL e Oracle lo consentono , se una colonna è UNICA) Quindi è necessario definire questa colonna INDICE UNICO NULL


1
MS-SQL consente più valori NULL in una colonna con un indice univoco, come ogni RDBMS. Pensala in questo modo: NULL non è un valore, quindi quando inserisci un secondo NULL, non corrisponderà mai a uno esistente. L'espressione (NULL == NULL) non viene valutata su vero o falso, ma su NULL.
gregmac,

grazie gregmac, non ero sicuro, se MS segue questo. Mi sono ricordato di alcuni MS Quirks con questo, tuttavia alcuni anni fa (prima del 2000) e potrebbe anche essere una vecchia tosse di
Peter Parker,

2

Non esiste una chiave primaria nella teoria dei dati relazionali, quindi la tua domanda deve avere una risposta a livello pratico.

Gli indici univoci non fanno parte dello standard SQL. La particolare implementazione di un DBMS determinerà quali sono le conseguenze della dichiarazione di un indice univoco.

In Oracle, la dichiarazione di una chiave primaria comporterà la creazione di un indice univoco per tuo conto, quindi la domanda è quasi controversa. Non posso parlarti di altri prodotti DBMS.

Preferisco dichiarare una chiave primaria. Ciò ha l'effetto di vietare NULL nelle colonne chiave e di vietare i duplicati. Favorisco inoltre la dichiarazione dei vincoli di RIFERIMENTI per imporre l'integrità dell'entità. In molti casi, la dichiarazione di un indice sul coulmn (s) di una chiave esterna accelererà i join. Questo tipo di indice non dovrebbe in generale essere unico.


Una chiave primaria in MS SQL Server è sempre sia UNIQUE che NOT NULL, ad esempio in realtà è solo un indice univoco, ma con l'aggiunta della restrizione che non può essere NULL.
marc_s

Oracle può applicare un vincolo univoco con un indice non univoco. Sarei sorpreso se MSSS non potesse. Dire "è davvero solo un indice univoco" è un disservizio.

"In molti casi, dichiarare un indice sul coulmn (s) di una chiave esterna accelererà i join." questo non è quasi sempre vero in un mondo di data warehousing in cui si preferirebbero hash join se disponibili.
JAC2703,

L'OP non ha menzionato i magazzini. Non sono sicuro di come funzionano i lombi di hash su SQL Server. Quanta parte del lavoro può essere eseguita al momento dell'aggiornamento del magazzino.
Walter Mitty,

2

Ci sono alcuni svantaggi degli INDICI CLUSTERATI rispetto agli INDICI UNICI.

Come già detto, un INDICE CLUSTER ordina fisicamente i dati nella tabella.

Ciò significa che quando si ha molto se si inserisce o elimina una tabella contenente un indice cluster, ogni volta (beh, quasi, a seconda del fattore di riempimento) si modificano i dati, la tabella fisica deve essere aggiornata per rimanere ordinata.

Nelle tabelle relativamente piccole, questo va bene, ma quando si arriva a tabelle con dati GB di dati e inserzioni / eliminazioni influiscono sull'ordinamento, si verificheranno problemi.


Qual è il vantaggio, allora? le query ordinate sono più veloci? è meglio per un caso d'uso quando scrivi la maggior parte dei tuoi dati una volta (o raramente) e li interroghi continuamente?
Buffalo,

1

Non creo quasi mai una tabella senza una chiave primaria numerica. Se esiste anche una chiave naturale che dovrebbe essere unica, inserisco anche un indice univoco. I join sono più veloci sugli interi rispetto alle chiavi naturali a più colonne, i dati devono solo cambiare in un posto (le chiavi naturali tendono ad essere aggiornate, il che è un male quando si trova nella chiave primaria - relazioni con le chiavi esterne). Se hai bisogno di una replica usa un GUID invece di un numero intero, ma per la maggior parte preferisco una chiave che sia leggibile dall'utente, specialmente se hanno bisogno di vederla per distinguere tra John Smith e John Smith.

Le poche volte in cui non creo una chiave surrogata sono quando ho una tabella di join che è coinvolta in una relazione molti-a-molti. In questo caso dichiaro entrambi i campi come chiave primaria.


"Non creo quasi mai una tabella senza una chiave primaria numerica": perché sempre numerici? Una chiave primaria non deve essere numerica (né deve essere AUTO_INCREMENT a proposito).
Hibou57,

@ Hinou57, perché ho scoperto che le chiavi naturali raramente in realtà sono uniche e che sono quasi sempre modificabili. Ulteriori join su interger sono generalmente molto più veloci di join su varcahrr chiavi naturali o peggiori tasti compositi. Non li userei quasi sempre. Ciò può variare in base al tipo di informazioni archiviate nel database, ma nella mia esperienza personale ho scoperto che le chiavi naturali sono estremamente inaffidabili nel tempo.
HLGEM,

Grazie per la risposta HLGEM. Cosa intendi con inaffidabile? Prestazione? (Spero che non sia una questione di affidabilità nel senso di integrità dei dati). Sono un po 'sorpreso dalle tue parole, poiché anche se uso chiavi intere o chiavi più naturali come VARCHAR breve, probabilmente farebbe solo una piccola differenza poiché l'hashing viene utilizzato ovunque anche con i motori DB più semplici.
Hibou57,

In molti casi sono inaffidabili perché non sono affidabili in modo univoco, anche se si suppone che lo siano. Sono inaffidabili perché cambiano e ciò può influenzare milioni di record in una data aggiornata. Questa è la mia esperienza avendo visto e gestito o interrogato dati da o importati da centinaia di database che memorizzano dati su molti tipi diversi di informazioni.
HLGEM,

1

La mia comprensione è che una chiave primaria e un indice univoco con un vincolo non nullo sono uguali (*); e suppongo che uno scelga l'uno o l'altro a seconda di ciò che la specifica afferma esplicitamente o implica (una questione di ciò che si desidera esprimere ed applicare esplicitamente). Se richiede unicità e non null, quindi renderlo una chiave primaria. Se succede semplicemente che tutte le parti di un indice univoco non sono nulle senza alcun requisito, allora rendilo un indice univoco.

L'unica differenza rimanente è che potresti avere più indici univoci non nulli, mentre non puoi avere più chiavi primarie.

(*) Tranne una differenza pratica: una chiave primaria può essere la chiave univoca predefinita per alcune operazioni, come la definizione di una chiave esterna. Ex. se si definisce una chiave esterna che fa riferimento a una tabella e non fornisce il nome della colonna, se la tabella a cui si fa riferimento ha una chiave primaria, la chiave primaria sarà la colonna a cui si fa riferimento. Altrimenti, la colonna referenziata dovrà essere nominata esplicitamente.

Altri qui hanno menzionato la replica di DB, ma non ne sono a conoscenza.


0

L'indice univoco può avere un valore NULL. Crea un INDICE NON CLUSTERATO. La chiave primaria non può contenere valore NULL. Crea l'INDICE CLUSTERATO.


0

In MSSQL, le chiavi primarie dovrebbero aumentare monotonicamente per ottenere le migliori prestazioni sull'indice cluster. Pertanto un numero intero con inserimento dell'identità è migliore di qualsiasi chiave naturale che potrebbe non aumentare in modo monotonico.


-1

Se dipendesse da me ...

Devi soddisfare i requisiti del database e delle tue applicazioni.

L'aggiunta di un numero intero con incremento automatico o di una colonna id lunga a ogni tabella per fungere da chiave primaria si occupa dei requisiti del database.

Aggiungere quindi almeno un altro indice univoco alla tabella per l'utilizzo da parte dell'applicazione. Questo sarebbe l'indice su employee_id, account_id o customer_id, ecc. Se possibile, questo indice non dovrebbe essere un indice composito.

Preferirei gli indici su più campi individualmente rispetto agli indici compositi. Il database utilizzerà gli indici a campo singolo ogni volta che la clausola where include tali campi, ma utilizzerà un composito solo quando si forniscono i campi esattamente nell'ordine corretto, il che significa che non può utilizzare il secondo campo in un indice composito a meno che non si fornisca sia il primo che il secondo nella clausola where.

Sono tutti per l'utilizzo di indici calcolati o di tipo Funzione e consiglierei di usarli su indici compositi. Rende molto facile usare l'indice di funzione usando la stessa funzione nella clausola where.

Questo si occupa dei requisiti dell'applicazione.

È molto probabile che altri indici non primari siano in realtà mappature di tale indice indicando il valore della chiave su un valore della chiave primaria, non su rowid (). Ciò consente di eseguire operazioni di ordinamento fisico ed eliminazioni senza dover ricreare questi indici.

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.