Utilizzare l'indirizzo e-mail come chiave primaria?


234

L'indirizzo e-mail è un cattivo candidato per il primario rispetto ai numeri con incremento automatico?

La nostra applicazione web richiede che l'indirizzo e-mail sia univoco nel sistema. Quindi, ho pensato di usare l'indirizzo e-mail come chiave primaria. Tuttavia il mio collega suggerisce che il confronto delle stringhe sarà più lento del confronto dei numeri interi.

È un motivo valido per non utilizzare l'e-mail come chiave primaria?

Stiamo usando PostgreSQL.


5
Cosa intendi con "primario"? Se l'indirizzo e-mail deve essere univoco, è una chiave e richiede un vincolo univoco. Indipendentemente dal fatto che tu decida di "promuovere" che sia "primario" è arbitrario, a meno che non vi sia una ragione pratica per farlo, ad esempio l'ottimizzazione di un sistema con prestazioni scarse.
onedayquando il

7
Se si desidera che il proprio database imponga un indirizzo e-mail univoco, creare una colonna con un indice univoco, ma non utilizzarlo come chiave primaria.
James Westgate,

104
@robert Cosa succede se qualcuno vuole cambiare il suo indirizzo email? Cambierete anche tutte le chiavi esterne?
systempuntoout,

3
@onedaywhen - quasi nessuna differenza, ma la chiave primaria verrà raggruppata per impostazione predefinita, mentre un indice univoco non lo sarà. Si vorrà comunque definire la chiave primaria che sarà la chiave di ricerca del singolo record predefinita, l'indice univoco impone semplicemente l'univocità della colonna su un indice normale
James Westgate,

3
@James Westgate: Cordiali saluti, non esiste il clustering automatico in PostgreSQL. Un PRIMARY KEY è implementato sul disco esattamente come un INDICE UNICO in cui tutti i campi NON sono NULL.
Matthew Wood,

Risposte:


283

Il confronto delle stringhe è più lento del confronto int. Tuttavia, questo non importa se si recupera semplicemente un utente dal database utilizzando l'indirizzo e-mail. È importante se hai query complesse con più join.

Se si memorizzano informazioni sugli utenti in più tabelle, le chiavi esterne della tabella degli utenti saranno l'indirizzo e-mail. Ciò significa che memorizzi più volte l'indirizzo e-mail.


11
@Sjoerd: Il problema non è che l'indirizzo e-mail viene archiviato più volte, anche se sicuramente è inefficiente, ma a chi importa oggi lo spazio sul disco rigido. La maggior parte delle aziende non ha una scala di Google, dove questo sarebbe importante. Il problema è che l'indirizzo e-mail non può essere modificato in seguito, poiché è sia una chiave primaria che una chiave esterna.
Stefan Steiger,

@StefanSteiger Chi ha detto qualcosa sullo spazio sul disco rigido? Tutto ciò che memorizzi occuperà spazio nella RAM.
Jonathan Allen

Nel caso qualcuno si chieda, come ho fatto io, una chiave GUID sarebbe equivalente a una chiave di posta elettronica credo.
martedì

178

Sottolineerò anche che l'e-mail è una cattiva scelta per creare un campo unico, ci sono persone e persino piccole imprese che condividono un indirizzo e-mail. E come i numeri di telefono, le e-mail possono essere riutilizzate. Jsmith@somecompany.com può facilmente appartenere a John Smith un anno e Julia Smith due anni dopo.

Un altro problema con le e-mail è che cambiano frequentemente. Se ti unisci ad altre tabelle con questo come chiave, allora dovrai aggiornare anche le altre tabelle, il che può essere un notevole successo in termini di prestazioni quando un'intera azienda client modifica le loro e-mail (cosa che ho visto accadere).


47
+1 per menzionare il problema dell'aggiornamento a cascata. Ecco perché gli amici consentono agli amici di usare solo chiavi surrogate ;-).
sleske,

10
ah, non mi piace affatto il detto ... le chiavi surrogate possono anche essere la fonte di problemi; sì, l'applicazione sarà più robusta per il cambiamento delle regole aziendali e / o di integrità, tuttavia le informazioni possono perdersi un po 'più facilmente e l'identità dei record diventa meno chiara. quindi non consiglierei una regola empirica qui ...
Unreason,

12
@onedaywhen e @jay, solo perché pensi che dovrebbe essere unico, non renderlo unico. E sì, marito e moglie potrebbero essere clienti diversi. Solo perché non ti sei mai imbattuto in questo prima non significa che non accadrà. Mi sono imbattuto in esso e succede che è per questo che l'e-mail non dovrebbe mai essere considerata unica se pensi che dovrebbe essere o meno. Questo è il tipo di requisito che si respinge perché è intrinsecamente sbagliato.
HLGEM,

15
@HLGEM: Non voglio entrare in una discussione senza fine, ma non puoi dire che una chiave proposta non sia unica sulla base di ipotesi senza conoscere il contesto. ad es. dal punto di vista della compagnia telefonica, un numero di telefono identifica in modo univoco un cliente, per definizione. Sì, puoi dire "Ma cosa succede se ci sono due o tre persone che potrebbero rispondere quando chiami quel numero?" Ma questo è irrilevante. Dal punto di vista della compagnia telefonica, questo è per definizione un cliente. (continua ...)
Jay,

14
(continua) Allo stesso modo, se stai costruendo un sistema che è in gran parte interessato alle comunicazioni e-mail - forse un sistema di invio di messaggi o un sistema di inoltro di notifiche - è probabile che, per definizione, un indirizzo e-mail identifichi in modo univoco un utente. Se più persone condividono quell'indirizzo e-mail, ciò è irrilevante. Sono una destinazione a messaggio singolo, quindi sono un singolo utente. "Utente" e "cliente" non devono essere sinonimi di "individuo umano".
Jay,

99

la chiave primaria dovrebbe essere unica e costante

gli indirizzi email cambiano come le stagioni. Utile come chiave secondaria per la ricerca, ma una scelta sbagliata per la chiave primaria.


17
Una proprietà di una buona chiave è che dovrebbe essere stabile ma NON necessariamente immutabile.
onedayquando il

5
@onedaywhen: Yep! Altrimenti perché SQL dovrebbe supportare gli aggiornamenti a cascata?
Bill Karwin,

18
se hai una scelta, scegli chiavi costanti / immutabili; meno lavoro per te lungo la strada; solo perché SQL supporta gli aggiornamenti a cascata non significa che sia sempre una buona idea!
Steven A. Lowe,

7
@Vincent Malgrat: "aggiornamenti a cascata ... normalizzazione freni db" - mi sembra che tu abbia frainteso il concetto di normalizzazione!
onedayquen

5
@Vincent Malgrat: grazie per aver confermato di aver frainteso il concetto di normalizzazione. "non dovresti avere le stesse informazioni ripetute su più righe" - intendevi davvero dire "informazioni" ?! Una chiave composta di solito implica valori ripetuti su più righe. Per una chiave esterna, i valori sono referenziati piuttosto che "ripetuti", grande differenza. Un dominio a colonna singola con due valori (ad esempio "Sì" e "No") avrà gli stessi valori su più righe in una tabella di riferimento se ha tre o più righe. Questa è roba davvero di base!
Onedayquen

64

Svantaggi dell'utilizzo di un indirizzo e-mail come chiave primaria:

  1. Più lento quando si eseguono join.

  2. Qualsiasi altro record con una chiave esterna registrata ora ha un valore maggiore, occupando più spazio su disco. (Dato il costo dello spazio su disco oggi, questo è probabilmente un problema banale, tranne nella misura in cui il record ora impiega più tempo a leggere. Vedi # 1.)

  3. Un indirizzo e-mail potrebbe cambiare, costringendo tutti i record a utilizzarlo come chiave esterna per essere aggiornati. Poiché l'indirizzo e-mail non cambia molto spesso, il problema delle prestazioni è probabilmente minore. Il problema più grande è che devi assicurarti di provvedere. Se devi scrivere il codice, questo è più lavoro e introduce la possibilità di bug. Se il tuo motore di database supporta "on update cascade", è un problema minore.

Vantaggi dell'utilizzo dell'indirizzo e-mail come chiave primaria:

  1. Potresti essere in grado di eliminare completamente alcuni join. Se tutto ciò di cui hai bisogno dal "record master" è l'indirizzo e-mail, allora con una chiave intera astratta dovresti fare un join per recuperarlo. Se la chiave è l'indirizzo e-mail, allora l'hai già e il join non è necessario. Se questo ti aiuta dipende dalla frequenza con cui si presenta questa situazione.

  2. Quando si eseguono query ad hoc, è facile per un essere umano vedere a quale master record viene fatto riferimento. Questo può essere di grande aiuto quando si cerca di rintracciare i problemi dei dati.

  3. Quasi sicuramente avrai bisogno di un indice sull'indirizzo e-mail, quindi renderlo la chiave primaria elimina un indice, migliorando così le prestazioni degli inserti in quanto ora hanno solo un indice da aggiornare invece di due.

Secondo la mia modesta opinione, in ogni caso non è una schiacciata. Tendo a preferire l'uso di chiavi naturali quando è disponibile una pratica perché sono semplicemente più facili da lavorare e gli svantaggi tendono a non avere molta importanza nella maggior parte dei casi.


@Conrad: Anche se, sottolinea che non è un PITA se hai un motore che supporta ON UPDATE CASCADE. È un problema a quel punto dal punto di vista del codice; l'unico vero problema è la portata dell'aggiornamento e la larghezza della chiave. L'indirizzo e-mail potrebbe essere un po 'troppo, ma un AGGIORNAMENTO CASCADE per un codice paese di 2 caratteri PK non è un grosso problema.
Matthew Wood,

5
@Matthew IMHO è ancora una PITA. Ad esempio, supponiamo che quando hai progettato la tua tabella del paese ci fossero solo due tabelle a cui faceva riferimento, senza problemi, ma nel tempo sono diventate 20 tabelle ognuna con centinaia di migliaia di record. Alcuni con il riferimento alcuni senza. Questo fa sì che una singola scrittura logica finisca per essere decine di migliaia di scritture e non arriva a tutte le tabelle perché qualcuno ha dimenticato un riferimento quando ha aggiunto la tabella. Questa è la cosa esatta che mi è successa su una tabella di codici paese di 2 caratteri che non ti prendo in giro.
Conrad Frix,

@Wood & Conrad: il caso peggiore è quando non c'è supporto DB integrato. Quindi devi scrivere il codice per ogni tabella con un riferimento pubblicato, e questo è solo un dolore e una porta per far entrare i bug. Con le cascate, devi solo ricordare di aggiungere una clausola su ogni tabella, non tale un grande affare.
Jay,

2
I vantaggi 1 e 3 sono ottimizzazioni premature, il vantaggio 2 è un vantaggio molto minore ed è completamente superato da qualsiasi strumento di query decente.
Ash,

4
@Ash: c'è una differenza tra "optimizatin" e "ottimizzazione prematura". Ma ok, con lo stesso ragionamento, tutti gli svantaggi che ho visto menzionare sono ottimizzazioni premature. Quindi dove ti lascia? Per quanto riguarda il n. 2, trovo che la digitazione di join extra quando provo a fare query ad hoc sia una vera seccatura. I record hanno spesso più chiavi esterne, quindi potresti aver bisogno di più join per ottenere dati comprensibili. Se per "strumento di query decente" intendi uno che capisce quali dati vuoi vedere senza che tu te lo dica e magicamente fa i join per te, mi piacerebbe vedere come funziona.
Jay,

12

È piuttosto male. Supponiamo che alcuni provider di posta elettronica non funzionino. Gli utenti vorranno quindi cambiare la loro e-mail. Se hai usato l'e-mail come chiave primaria, tutte le chiavi esterne per gli utenti duplicheranno quell'e-mail, rendendo molto difficile cambiare ...

... e non ho nemmeno iniziato a parlare di considerazioni sulle prestazioni.


In che modo la modifica degli indirizzi e-mail causerebbe la presenza di duplicati? A meno che l'utente A non cambi il suo indirizzo e-mail, quindi l'utente B cambi la sua e-mail in modo che corrisponda al vecchio valore dell'utente A e gli aggiornamenti non vengano eseguiti in sequenza. Remoto possibile, immagino.
Jay,

2
Un riferimento di chiave esterna, per definizione, contiene il valore della chiave primaria della riga a cui fa riferimento. In altre parole, duplica il valore della chiave primaria. (Quindi la duplicazione non è causata dalla modifica del valore. Ma la modifica è più difficile a causa di questa duplicazione e del vincolo che la impone).
Meriton,

5
+1 per la riga "Supponiamo che un provider di posta elettronica non sia più attivo."
Reddy,

Questo non è un problema. Esiste il collegamento in cascata di chiavi esterne per risolvere questo problema. Se un utente modifica la propria e-mail, la modifica passerà in cascata a tutte le tabelle utilizzandola come chiave esterna.
Rafa,

1
@rafa, ti assicuro che se usi aggiornamenti a cascata e un intero fornitore fallisce o cambia il suo nome (Yahoo.com diventa HooYa.com), il tuo database sarà bloccato a tutti gli utenti per ore e forse giorni mentre questo è in cascata attraverso il sistema. È un problema molto valido (e un motivo per cui è una cattiva idea utilizzare gli aggiornamenti a cascata se si dispone di una quantità significativa di dati e la chiave potrebbe cambiare.)
HLGEM

12

Non so se questo potrebbe essere un problema nella tua configurazione, ma a seconda del tuo RDBMS i valori di una colonna potrebbero essere case sensitive . I documenti PostgreSQL dicono: "Se dichiari una colonna come UNIQUE o PRIMARY KEY, l'indice generato implicitamente fa distinzione tra maiuscole e minuscole". In altre parole, se si accetta l'input dell'utente per una ricerca in una tabella con e-mail come chiave primaria e l'utente fornisce "John@Doe.com", non si troverà "john@doe.com".


7
Vale la pena ricordare a questo proposito che John@Doe.com e john@Doe.com potrebbero essere la stessa casella di posta o potrebbero essere caselle di posta diverse e non si ha modo di dirlo: non c'è nulla nelle specifiche per dire se la parte locale è case- sensibile.
telent

Questo è più un problema generale con l' applicazione dell'unicità degli indirizzi e-mail piuttosto che se debbano essere usati come chiavi primarie - lo stesso problema è presente in entrambi i modi. +1 perché è ancora un punto molto utile

11

Nessuno sembra aver menzionato un possibile problema per cui gli indirizzi e-mail potrebbero essere considerati privati. Se l'indirizzo e-mail è la chiave primaria, molto probabilmente un URL della pagina del profilo avrà un aspetto simile ..../Users/my@email.com. Cosa succede se non si desidera esporre l'indirizzo e-mail dell'utente? Dovresti trovare un altro modo per identificare l'utente, possibilmente con un valore intero univoco per rendere simili gli URL ..../Users/1. Quindi alla fine si otterrebbe un valore intero univoco.


9

A livello logico , l'e-mail è la chiave naturale. A livello fisico , dato che si sta utilizzando un database relazionale, la chiave naturale non si adatta bene come chiave primaria. Il motivo è principalmente i problemi di prestazioni menzionati da altri.

Per tale motivo, il design può essere adattato. La chiave naturale diventa la chiave alternativa (UNIQUE, NOT NULL) e si utilizza una chiave surrogata / artificiale / tecnica come chiave primaria, che può essere un auto-incremento nel proprio caso.

systempuntoout ha chiesto,

Cosa succede se qualcuno vuole cambiare il suo indirizzo email? Cambierete anche tutte le chiavi esterne?

Ecco a cosa serve la cascata .

Un altro motivo per utilizzare una chiave surrogata numerica come chiave primaria è legato al funzionamento dell'indicizzazione nella piattaforma. In InnoDB di MySQL, ad esempio, tutti gli indici in una tabella hanno la chiave primaria pre-attesa, quindi vuoi che il PK sia il più piccolo possibile (per motivi di velocità e dimensioni). Anche in relazione a questo, InnoDB è più veloce quando la chiave primaria è memorizzata in sequenza, e una stringa non ci sarebbe di aiuto.

Un'altra cosa da prendere in considerazione quando si utilizza una stringa come chiave alternativa, è che l'uso di un hash della stringa effettiva desiderata potrebbe essere più veloce, saltando cose come maiuscole e minuscole di alcune lettere. (Sono effettivamente atterrato qui mentre cercavo un riferimento per confermare quello che ho appena detto; ancora alla ricerca ...)


5

Sì, è una chiave primaria errata perché gli utenti vorranno aggiornare i loro indirizzi e-mail.


1
Ho pensato di sottolineare che ora abbiamo a cascata questo non è un problema
malhal

4

sì, è meglio se usi invece un numero intero. puoi anche impostare la colonna e-mail come vincolo univoco.

come questo:

CREATE TABLE myTable(
    id integer primary key,
    email text UNIQUE
);

8
Perché è "migliore"? Qualche motivo o fonte?
Sjoerd,

20
Puoi approfondire questo?
Sjoerd,

3

Un altro motivo per cui la chiave primaria intera è migliore è quando si fa riferimento all'indirizzo e-mail in una tabella diversa. Se l'indirizzo stesso è una chiave primaria, in un'altra tabella devi usarlo come chiave. Quindi memorizzi gli indirizzi e-mail più volte.


3

Non ho troppa familiarità con Postgres. Le chiavi primarie sono un argomento importante. Ho visto alcune domande e risposte eccellenti su questo sito (stackoverflow.com).

Penso che potresti avere prestazioni migliori avendo una chiave primaria numerica e utilizzando un INDICE UNICO nella colonna e-mail. Le e-mail tendono a variare in lunghezza e potrebbero non essere appropriate per l'indice della chiave primaria.

qualche lettura qui e qui.


3

Personalmente, non utilizzo alcuna informazione per la chiave primaria durante la progettazione del database, perché è molto probabile che possa essere necessario modificare qualsiasi informazione in un secondo momento. L'unica ragione per cui fornisco la chiave primaria è che è conveniente eseguire la maggior parte delle operazioni SQL dal lato client e la mia scelta è sempre stata il tipo intero con incremento automatico.


2

Il tuo collega ha ragione: usa un numero intero autoincrementante per la tua chiave primaria.

È possibile implementare l'unicità della posta elettronica a livello di applicazione oppure contrassegnare la colonna dell'indirizzo e-mail come univoca e aggiungere un indice su quella colonna.

L'aggiunta del campo come univoco ti costerà il confronto delle stringhe solo quando si inserisce in quella tabella e non quando si eseguono join e controlli dei vincoli di chiave esterna.

Ovviamente, è necessario notare che l'aggiunta di eventuali vincoli all'applicazione a livello di database può rendere l'app non flessibile. Prendi sempre la dovuta considerazione prima di rendere qualsiasi campo "unico" o "non nullo" solo perché la tua applicazione deve essere unica o non vuota.


1
"Prendi sempre la dovuta considerazione prima di implementare il requisito x solo perché l'applicazione richiede il requisito x." - il peggior consiglio che ho letto da un po 'di tempo.
onedayquando il

Non sono convinto dal tuo "argomento" - nella vita reale ci saranno spesso situazioni in cui alcuni dati essenziali (ad esempio un numero di telefono) non saranno immediatamente disponibili. Se tale campo è contrassegnato come NOT NULL in un database, richiederà agli utenti di inquinare i dati con campi fittizi (come 123) invece di lasciarli vuoti. Sarebbe più pratico lasciare che l'applicazione gestisca i vincoli (e in questo caso, l'app potrebbe contrassegnare un campo vuoto come elemento di azione).
jrharshath,

5
Concordo sul fatto che la definizione di un campo "non nullo" dovrebbe essere effettuata con cautela. Requisiti come "abbiamo sempre bisogno del numero di telefono del cliente" devono essere considerati attentamente. Potrebbe non essere desiderabile a volte creare un record del cliente anche se non conosciamo il numero di telefono in questo momento, e tornare indietro e ottenerlo più tardi? Ma "questo campo deve essere unico" è una categoria diversa. Non riesco a immaginare di dire "Va bene per due dipendenti avere lo stesso numero di previdenza sociale, lo scopriremo più tardi". Come raddrizzeresti mai i dati?
Jay,

1
Be Wolves: una volta conoscevo una donna che non aveva il suo numero di telefono. Cosa fai allora?
David Thornley,

@DavidThornley Sembra che dovresti allenarti di più, o forse adattare un comportamento più amichevole.
Philip Schiff,

2

Usa un GUID come chiave primaria ... in questo modo puoi generarlo dal tuo programma quando esegui un INSERT e non hai bisogno di ottenere una risposta dal server per scoprire qual è la chiave primaria. Sarà anche unico attraverso tabelle e database e non devi preoccuparti di cosa succede se un giorno tronchi la tabella e l'incremento automatico viene ripristinato a 1.


2
A meno che non ti interessi poco o nulla delle prestazioni, usa un GUID. Non è il n. 1 se stai costruendo un sistema che dovrà essere ridimensionato
Michea il


3
Ha detto nella vera moda Microsoft-Kool-Aid-drinking!
Gary Chambers,

2

So che è un po 'tardi, ma vorrei aggiungere che le persone abbandonano gli account e-mail e i fornitori di servizi recuperano l'indirizzo consentendo a un'altra persona di usarlo.

Come ha sottolineato @HLGEM "Jsmith@somecompany.com può facilmente appartenere a John Smith un anno e Julia Smith due anni dopo". in questo caso, se John Smith desidera il tuo servizio, devi rifiutare di utilizzare il suo indirizzo e-mail o eliminare tutti i tuoi record relativi a Julia Smith.

Se devi eliminare i record e questi si riferiscono alla storia finanziaria dell'azienda in base alla legge locale, potresti ritrovarti in acqua calda.

Quindi non userei mai dati come indirizzi e-mail, targhe, ecc. Come chiavi primarie perché non importa quanto siano univoci fuori dal tuo controllo e in grado di fornire alcune sfide interessanti che potresti non avere il tempo di affrontare.


2

Potrebbe essere necessario prendere in considerazione qualsiasi normativa applicabile sulla regolamentazione dei dati. Le e-mail sono informazioni personali e, ad esempio, se i tuoi utenti sono cittadini dell'UE in base al GDPR, possono istruirti sull'eliminazione delle loro informazioni dai tuoi registri (ricorda che ciò vale indipendentemente dal paese in cui ti trovi).

Se è necessario conservare il record stesso nel database per integrità referenziale o motivi storici come l'audit, l'utilizzo di una chiave surrogata consentirebbe di NULL tutti i campi dei dati personali. Questo ovviamente non è facile se i loro dati personali sono la chiave primaria


1

è possibile migliorare le prestazioni utilizzando la chiave primaria intera.


1

dovresti usare una chiave primaria intera. se hai bisogno che la colonna e-mail sia univoca, perché non imposti semplicemente un indice univoco su quella colonna?


1

Se si dispone di un valore non int come chiave primaria, gli inserimenti e i recuperi saranno molto lenti su dati di grandi dimensioni.


1
No, inserisce sarà più lento , perché sono necessari due indici univoci: uno sulla chiave primaria generata e un altro sull'indirizzo e-mail.
a_horse_with_no_name

1

chiave primaria dovrebbe essere scelto un attributo statico. Poiché gli indirizzi e-mail non sono statici e possono essere condivisi da più candidati, non è una buona idea usarli come chiave primaria. Inoltre gli indirizzi e-mail sono stringhe di solito di una certa lunghezza che possono essere maggiori di un ID univoco che vorremmo usare [len (indirizzo_email)> len (unique_id)] ​​in modo da richiedere più spazio e, peggio ancora, vengono memorizzati più volte come chiave esterna . E di conseguenza porterà a degradare le prestazioni.


0

Dipende dal tavolo. Se le righe nella tabella rappresentano gli indirizzi e-mail, l'email è l'ID migliore. In caso contrario, l'e-mail non è un buon ID.


0

Se si tratta semplicemente di richiedere che l'email sia unica, puoi semplicemente creare un indice univoco con quella colonna.


0

L'e-mail è un buon candidato all'indice univoco, ma non per la chiave primaria, se si tratta di una chiave primaria, non sarà possibile, ad esempio, modificare l'indirizzo di posta elettronica del contatto. Penso che anche le tue domande di partecipazione saranno più lente.


0

non utilizzare l'indirizzo e-mail come chiave primaria, mantenere l'e-mail come unica ma non utilizzarla come chiave primaria, utilizzare l'id utente o il nome utente come chiave primaria

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.