Stringhe come chiavi primarie nel database SQL


178

Non ho molta familiarità con i database e le teorie su come funzionano. Dal punto di vista delle prestazioni (inserimento / aggiornamento / interrogazione) è più lento utilizzare le stringhe per chiavi primarie rispetto ai numeri interi?

Risposte:


192

Tecnicamente sì, ma se una stringa ha senso essere la chiave primaria, probabilmente dovresti usarla. Tutto dipende dalla dimensione della tabella per cui la stai realizzando e dalla lunghezza della stringa che diventerà la chiave primaria (stringhe più lunghe == più difficili da confrontare). Non userei necessariamente una stringa per una tabella che ha milioni di righe, ma la quantità di rallentamento delle prestazioni che otterrai utilizzando una stringa su tabelle più piccole sarà minuscola per il mal di testa che puoi avere avendo un numero intero che non non significa nulla in relazione ai dati.


11
non dipenderebbe dal database? Penserei che una stringa opportunamente indicizzata non sarebbe molto più lenta se non da un numero?
Ryan Guill,

2
Concordo sul fatto che ci sono molte variabili da considerare. (In sqlserver) abbiamo riscontrato problemi di prestazioni reali con l'utilizzo di stringhe con lunghezze da adolescenti medio-alte e superiori anche quando indicizzate. Acquista hai ragione, ci sono cose per superare questo hardware, ad esempio.
kemiller2002,

1
Giusto. Concordo però sul fatto che se una stringa ha un senso, questo è ciò che dovresti usare. Direi anche che ci sono sicuramente momenti per i campi GUID o UUID nei database in cui un campo di incremento automatico non funzionerebbe.
Ryan Guill,

7
Ricorda anche che spesso c'è una differenza molto grande tra un CHAR e un VARCHAR quando si effettuano confronti di indici
Tom H,

7
Il numero di commenti di questa risposta chiarisce quanto sia incompleta. L'indicizzazione delle menzioni sarebbe stata la risposta minima accettabile.
Pedro Rolo,

75

Un altro problema con l'utilizzo di stringhe come chiave primaria è che, poiché l'indice viene costantemente messo in ordine sequenziale, quando viene creata una nuova chiave che si troverebbe nel mezzo dell'ordine, l'indice deve essere reinviato ... se si utilizza un'auto numero intero, la nuova chiave viene appena aggiunta alla fine dell'indice.


2
Ciò può causare "punti critici" per i nuovi inserti. Finché gestisci correttamente il tuo database, dovresti avere comunque spazio extra sulle tue pagine per gli inserti e le divisioni delle pagine dovrebbero essere rare.
Tom H,

20
cioè quando le chiavi primarie sono raggruppate. puoi anche crearli senza cluster.
Apprendimento del

Sono ordinati XID che potrebbero essere d'aiuto se si usano solo stringhe di
xid

22

Inserisce in una tabella con un indice cluster in cui l'inserimento avviene nel mezzo della sequenza NON causa la riscrittura dell'indice. Non provoca la riscrittura delle pagine che comprendono i dati. Se c'è spazio nella pagina in cui andrà la riga, allora viene inserito in quella pagina. La singola pagina verrà riformattata per posizionare la riga nel posto giusto nella pagina. Quando la pagina è piena, si verificherà una divisione della pagina, con metà delle righe sulla pagina che va a una pagina e metà che va sull'altra. Le pagine vengono quindi ricollegate nell'elenco di pagine collegate che comprendono una tabella di dati che ha l'indice cluster. Al massimo, finirai per scrivere 2 pagine del database.


Buona spiegazione Ma è vero per tutti i database SQL? Ho sentito parlare di problemi di prestazioni di MySQL durante l'utilizzo di UUID casuale come chiave primaria.
hgoebl,

13

Le stringhe sono più lente nei join e nella vita reale sono molto raramente davvero uniche (anche quando dovrebbero essere). L'unico vantaggio è che possono ridurre il numero di join se ci si unisce alla tabella primaria solo per ottenere il nome. Tuttavia, anche le stringhe sono spesso soggette a modifiche, creando così il problema di dover correggere tutti i record correlati quando il nome dell'azienda cambia o la persona si sposa. Questo può essere un enorme successo in termini di prestazioni e se tutte le tabelle che dovrebbero essere correlate in qualche modo non sono correlate (ciò accade più spesso di quanto si pensi), è possibile che anche i dati non corrispondano. Un numero intero che non cambierà mai per tutta la durata del record è una scelta molto più sicura dal punto di vista dell'integrità dei dati e dal punto di vista delle prestazioni. Le chiavi naturali di solito non sono così buone per il mantenimento dei dati.

Voglio anche sottolineare che il meglio dei due mondi è spesso usare una chiave autoincrementante (o in alcuni casi specializzati, un GUID) come PK e quindi inserire un indice univoco sulla chiave naturale. Ottieni i join più veloci, non ottieni record duplicati e non devi aggiornare un milione di record figlio perché il nome di una società è cambiato.


26
Le stringhe che sono buoni candidati per i PK non hanno duplicati, altrimenti non sarebbero un buon candidato per un PK. Pensa a codici ICD-9, prefissi nazionali, numeri VIN. L'uso di un nome come esempio di un problema con le chiavi naturali non è corretto, perché non dovrebbero mai essere candidati in primo luogo.
Tom H,

6
@Tom H: i codici ISO County cambiano. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] Come risposta a una domanda correlata, ha dichiarato [ stackoverflow.com/questions/925266/… ] "Per PRIMARY KEY assicurati che la loro unicità sia sotto il tuo controllo"
Steve Schnepp

4
@SteveSchnepp: sì e l'ISO è l'organismo di fiducia per la gestione di tale modifica. D'altra parte, quando hai bisogno di unire la sequenza monotonica di incremento dei valori interi con quella di qualcun altro, sei da solo;)
onedaywh

1
Concordo sul fatto che i nomi non debbano essere considerati come una chiave, ho appena visto in molti casi in cui lo erano.
HLGEM,

1
@onedayquando l'unione di 2 sequenze monotoniche di numeri interi incrementali viene eseguita facilmente tramite prefisso o suffisso :)
Steve Schnepp

6

Non importa cosa usi come chiave primaria purché sia ​​UNICA. Se ti interessa la velocità o una buona progettazione del database, usa int a meno che non preveda di replicare i dati, quindi usa un GUID.

Se questo è un database di accesso o qualche piccola app, allora chi se ne frega davvero. Penso che la ragione per cui la maggior parte di noi sviluppatori schiaffeggia il vecchio int o guid in primo piano è perché i progetti hanno un modo di crescere su di noi e tu vuoi lasciarti l'opzione di crescere.


5

Troppe variabili. Dipende dalle dimensioni della tabella, dagli indici, dalla natura del dominio della chiave stringa ...

In generale , i numeri interi saranno più veloci. Ma la differenza sarà abbastanza grande da interessarti? È difficile da dire.

Inoltre, qual è la tua motivazione nella scelta delle stringhe? Anche i tasti numerici di autoincremento sono molto più semplici . È semantica? Convenienza? Problemi di replica / disconnessione? La tua risposta qui potrebbe limitare le tue opzioni. Ciò ricorda anche una terza opzione "ibrida" che stai dimenticando: le guide.


non ha senso cloutierm, cosa intendi?
HLGEM,

@HLGEM: Se lo capisco scrivere, intende sincronizzare i record creati su un laptop con il db principale.
Joel Coehoorn,

Voglio dire, ho due database separati con le stesse entità, solo uno viene aggiornato meno frequentemente per scopi di archiviazione persistente. Se chiedo l'entità "California" nel database A, voglio che sia fondamentalmente la stessa "California" nel database B.
mainstringargs,

1
Ed è 'come' sincronizzare i record creati in un laptop in quanto è lo stesso problema: i record creati in un posto non dovrebbero entrare in conflitto con quelli creati in un altro. Una possibile soluzione qui sono le chiavi Guid.
Joel Coehoorn,

5

Non preoccuparti delle prestazioni fino a quando non avrai ottenuto un design semplice e solido che concorda con l'oggetto che i dati descrivono e si adatta bene all'uso previsto dei dati. Quindi, se emergono problemi di prestazioni, è possibile gestirli modificando il sistema.

In questo caso, è quasi sempre meglio usare una stringa come chiave primaria naturale, a condizione che ci si possa fidare di essa. Non preoccuparti se si tratta di una stringa, a condizione che la stringa sia ragionevolmente corta, indica circa 25 caratteri al massimo. Non pagherai un grande prezzo in termini di prestazioni.

Le persone che inseriscono i dati o le origini dati automatiche forniscono sempre un valore per la presunta chiave naturale o talvolta vengono omesse? Occasionalmente è errato nei dati di input? In tal caso, come vengono rilevati e corretti gli errori?

I programmatori e gli utenti interattivi che specificano le query sono in grado di utilizzare la chiave naturale per ottenere ciò che desiderano?

Se non puoi fidarti della chiave naturale, inventa un surrogato. Se inventi un surrogato, potresti anche inventare un numero intero. Quindi devi preoccuparti di dove nascondere il surrogato alla comunità degli utenti. Alcuni sviluppatori che non hanno nascosto la chiave surrogata sono venuti a pentirsene.


3

Gli indici implicano molti confronti.

In genere, le stringhe sono più lunghe degli interi e le regole di confronto possono essere applicate per il confronto, quindi il confronto delle stringhe è di solito un'attività più intensiva dal punto di vista computazionale rispetto al confronto di interi.

A volte, tuttavia, è più veloce usare una stringa come chiave primaria che fare un ulteriore join con una string to numerical idtabella.


2

Sì, ma a meno che non ti aspetti di avere milioni di righe, non usare una chiave basata su stringhe perché è più lenta è di solito "ottimizzazione prematura". Dopotutto, le stringhe vengono memorizzate come numeri grandi mentre i tasti numerici vengono generalmente memorizzati come numeri più piccoli.

Una cosa a cui prestare attenzione, tuttavia, è se si dispone di indici raggruppati su una chiave qualsiasi e si sta eseguendo un numero elevato di inserimenti non sequenziali nell'indice. Ogni riga scritta farà riscrivere l'indice. se stai eseguendo inserimenti batch, questo può davvero rallentare il processo.


2

Due motivi per utilizzare numeri interi per le colonne PK:

  1. Possiamo impostare l'identità per il campo intero che viene incrementato automaticamente.

  2. Quando creiamo PK, il db crea un indice (Cluster o Non Cluster) che ordina i dati prima che vengano archiviati nella tabella. Utilizzando un'identità su un PK, l'ottimizzatore non deve controllare il criterio di ordinamento prima di salvare un record. Ciò migliora le prestazioni su grandi tavoli.


1

Qual è il motivo per cui hai una stringa come chiave primaria?

Vorrei solo impostare la chiave primaria su un campo intero a incremento automatico e inserire un indice sul campo stringa.

In questo modo, se esegui ricerche sul tavolo, dovrebbero essere relativamente veloci e tutti i tuoi join e le tue normali ricerche non saranno influenzati dalla loro velocità.

Puoi anche controllare la quantità del campo stringa che viene indicizzato. In altre parole, puoi dire "indicizza solo i primi 5 caratteri" se pensi che sarà sufficiente. Oppure, se i tuoi dati possono essere relativamente simili, puoi indicizzare l'intero campo.


3
Penso che mettere una chiave in intelligenza sia chiedere guai. Rimarranno unici? Hanno iniziato tutti i numeri di conto con l'abbreviazione dello stato all'inizio solo alla mossa del cliente. Aggiorna un campo - nessun problema - tutte quelle tabelle collegate dal numero di conto - che casino.
JeffO,

1
Un esempio di utilizzo di una stringa come PK potrebbe essere una tabella di impostazioni. ad esempio settingNamePK, isUserEditable, isCustomerEditable ecc. Quindi, se si desidera modificare il comportamento dell'impostazione "UPDATE setting SET ... WHERE settingNamePK = 'dailyWorkObligation'" è molto più semplice che dover usare gli ID e memorizzare da qualche parte la mappatura degli ID. Ovviamente potresti avere un PK intero e avere anche il nome dell'impostazione come un'altra chiave univoca.
MeatPopsicle l'

Dato che la chiave primaria è un numero intero auto-incrementato, anche gli inserti non dovrebbero essere influenzati dalla loro velocità?
Dennis,

Per gli sviluppatori curiosi di Rails, ecco come specificare una lunghezza dell'indice . Si noti che SQLite non supporta la lunghezza dell'indice.
Dennis,

1

Dal punto di vista delle prestazioni - Sì, la stringa (PK) rallenterà le prestazioni rispetto alle prestazioni ottenute utilizzando un numero intero (PK), dove PK ---> Chiave primaria.

Dal punto di vista dei requisiti - Anche se questa non è ancora una parte della tua domanda, vorrei menzionarla. Quando gestiamo enormi dati su diverse tabelle, generalmente cerchiamo il probabile insieme di chiavi che è possibile impostare per una determinata tabella. Ciò è dovuto principalmente al fatto che ci sono molte tabelle e per lo più ciascuna o una tabella sarebbe correlata all'altra attraverso una relazione (un concetto di chiave esterna). Pertanto, non possiamo sempre scegliere un numero intero come chiave primaria, piuttosto optiamo per una combinazione di 3, 4 o 5 attributi come chiave primaria per quelle tabelle. E quelle chiavi possono essere usate come chiave esterna quando mettiamo in relazione i record con qualche altra tabella. Ciò rende utile mettere in relazione i record tra diverse tabelle quando richiesto.

Pertanto per un utilizzo ottimale: creiamo sempre una combinazione di 1 o 2 numeri interi con 1 o 2 attributi di stringa, ma di nuovo solo se necessario.


0

Potrebbe esserci un grosso malinteso relativo alla stringa nel database. Quasi tutti hanno pensato che la rappresentazione dei numeri nel database sia più compatta che per le stringhe. Pensano che nei numeri db-s siano rappresentati come nella memoria. Ma non è vero. Nella maggior parte dei casi la rappresentazione numerica è più vicina ad una stringa come la rappresentazione rispetto ad altre.

La velocità di utilizzo di numero o stringa dipende più dall'indicizzazione che dal tipo stesso.


0

Per impostazione predefinita, ASPNetUserIds sono stringhe di 128 caratteri e le prestazioni vanno bene.

Se la chiave DEVE essere univoca nella tabella, dovrebbe essere la chiave. Ecco perché;

chiave stringa primaria = relazioni DB corrette, 1 chiave stringa (primaria) e 1 indice indice (primaria).

L'altra opzione è una tipica chiave int, ma se la stringa DEVE essere univoca probabilmente dovrai comunque aggiungere un indice a causa di query non-stop per convalidare o verificare che sia univoco.

Quindi, usando una chiave di identità int = Relazioni DB errate, 1 chiave int (Primaria), 1 indice int (Primaria), Probabilmente un indice stringa univoco e dover convalidare manualmente la stessa stringa non esiste (qualcosa come un controllo sql forse ).

Per ottenere prestazioni migliori usando un int su una stringa per la chiave primaria, quando la stringa DEVE essere univoca, dovrebbe essere una situazione molto strana. Ho sempre preferito usare le chiavi di stringa. E come una buona regola empirica, non denormalizzare un database fino a quando non BISOGNO a.

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.