2010-11-05 14 views
46

Sto frequentando un corso chiamato "sistemi di database" e per il nostro progetto di classe devo progettare un sito web.Perché utilizzare una chiave primaria a incremento automatico quando esistono altri campi univoci?

Ecco un esempio di una tabella che ho creato:

CREATE TABLE users 
(
    uid INT NOT NULL AUTO_INCREMENT, 
    username VARCHAR(60), 
    passhash VARCHAR(255), 
    email VARCHAR(60), 
    rdate DATE, 
    PRIMARY KEY(uid) 
); 

Il professore mi ha detto "uid" (user id) è stato completamente inutile e non necessaria e ho dovuto usare il nome utente come chiave primaria, dal momento che nessun due utenti possono avere lo stesso nome utente.

Gli ho detto che per me era conveniente usare un id utente perché quando chiamo qualcosa come domain.com/viewuser?id=5 ho semplicemente controllato il parametro con: is_numeric($_GET['id']) ... inutile dire che non era convinto.

Dal momento che ho visto user_id e altri attributi simili (thread_id, comment_id, tra gli altri) su un sacco di tutorial e guardando lo schema del database del software popolare (ad esempio vbulletin) ci devono essere molti altri motivi (più forti) .

Quindi la mia domanda è: come giustificheresti la necessità di un id incrementale non nullo come chiave primaria rispetto a un altro attributo come il nome utente?

+1

Joe Celko ha sempre emesso la stessa cosa, "Dovresti usare PK significativi quando possibile". – Brettski

+1

il tuo professore è troppo letto nel libro di fumetti che legge PHP/MySQL? – klox

+0

Il tuo professore sembra un purista. Relativamente, sì - se i nomi utente saranno unici, gli ID utente sono dati duplicati di un ordinamento, poiché il nome utente e l'ID utente hanno lo stesso significato. Ma nel mondo reale, sono utili per la maggior parte se non per tutti i motivi menzionati di seguito. – cHao

risposta

79

incremento automatico chiavi primarie sono utili per diversi motivi:

  • Permettono nomi utente duplicati come su Stack Overflow
  • Permettono il nome utente (o l'indirizzo e-mail, se è utilizzato per il login) per essere cambiato (facilmente)
  • sceglie, si unisce e gli inserti sono più veloci di chiavi primarie varchar come la sua molto più veloce per mantenere un indice numerico
  • come lei ha ricordato, la convalida diventa molto semplice: if ((int)$id > 0) { ... }
  • Sanitation di ingresso è banale: $id = (int)$_GET['id']
  • C'è molto meno spese generali come chiavi esterne non devono duplicare potenzialmente stringa di grandi dimensioni Valori

direi cercando di utilizzare ogni informazione stringa come un unico l'identificatore di un record è una cattiva idea quando un tasto numerico auto-incrementante è così facilmente disponibile.

I sistemi con nomi utente univoci vanno bene per un numero molto piccolo di utenti, ma Internet li ha resi fondamentalmente danneggiati. Se consideri il numero di persone chiamato "john" che potrebbe dover interagire con un sito Web, è ridicolo richiedere a ciascuno di loro di utilizzare un nome visualizzato univoco. Porta al terribile sistema che vediamo così frequentemente con cifre casuali e lettere che decorano un nome utente.

Tuttavia, anche in un sistema in cui sono stati imposti nomi utente univoci, è ancora una scelta scadente per una chiave primaria. Immagina un utente con 500 post: la chiave esterna nella tabella posts conterrà il nome utente, duplicato 500 volte. Il sovraccarico è proibitivo anche prima di considerare che qualcuno potrebbe dover cambiare nome utente.

+24

Dire al "professore" di leggere questa risposta;) – subosito

+8

Un altro punto: gli ORM odiano i tasti non interi. Anche se ritengo che questo sia un difetto generale da parte della maggior parte degli ORM, si impara a lavorare * con * gli strumenti – Phil

+1

@meagar odio visitare siti che mi richiedono di creare un nome utente univoco per l'accesso. Mi piacerebbe per abbandonare completamente il "nome utente" per l'autenticazione e passare solo all'indirizzo di posta elettronica. – Phil

15

Se il nome utente è la chiave primaria e un utente cambia il proprio nome utente, è necessario aggiornare tutte le tabelle che hanno riferimenti di chiavi esterne alla tabella utenti.

+8

Se l'utente può modificare il proprio nome utente, il nome utente non è una chiave primaria candidata. –

+6

L'azione referenziale 'ON UPDATE CASCADE' è la solita risposta a questo argomento 'uomo di paglia'. – onedaywhen

+4

@Bob Jarvis: una proprietà di una buona chiave che i valori sono stabili. Immutabile è l'ideale, ma anche i cambiamenti rari sono buoni. – onedaywhen

4

Perché qualcuno potrebbe voler cambiare il nome utente (o qualsiasi altro nome).

0

Ad esempio, la ricerca di numeri interi (? Id = 5) è molto più veloce e ha una cardinalità più elevata rispetto alla ricerca stringa (? Username = bob). Un altro esempio, uid è auto_increment, quindi non è necessario inserirlo esplicitamente, ma verrà incrementato automaticamente in ogni query di inserimento.

PS: Il tuo prof è veramente sbagliato su di esso: D

+1

Se sono unici, la carnalità della stringa o del numero sarebbe la stessa. Se viene utilizzato un indice di hash in ogni caso, la performance di ricerca sarebbe all'incirca la stessa in ciascun caso. Quindi, sulle informazioni fornite non vi è alcuna base per dire che uno è più veloce dell'altro. In ogni caso, il punto della questione è la correttezza, non la prestazione. Il professore è talmente bene! – sqlvogel

+0

@dportas, quindi sei il professore in questione? Il professore ha talmente torto che lo licenzierei se provasse a fare qualcosa di così stupido nei miei database. – HLGEM

+1

@HLGEM: Io non sono lui, ma potrei considerare di licenziare qualcuno che è stato così stupido da permettere a utenti duplicati in una tabella utente - o almeno lo avrei rieducato facendoli definire chiavi naturali prima delle surrogate. Mi aspetto che il prof si senta allo stesso modo. – sqlvogel

1

avrò bisogno di qualcuno con più conoscenza database per me il backup su questo, ma credo che si ottiene una risposta più veloce nel tempo di ricerca di chiavi esterne.

Inoltre, è possibile decidere in seguito che si desidera modificare i nomi utente o che i requisiti per i nomi utente potrebbero cambiare (forse una stringa più lunga?). L'uso di un ID impedisce di dover cambiare tutte le chiavi esterne.

lascia la faccia esso, la maggior parte dei progetti non sono in corso per espandere che molto, ma non si vuole veramente rischiare il mal di testa 12 mesi lungo la strada, quando si poteva essere conformi alle norme di buona programmazione ora?

+1

VARCHAR (4) accetta il numero di byte pari a INT; meno che sia più piccolo di INT ma ciò non lo rende fattibile a seconda delle regole. –

+0

Ovviamente questo è varchar (60) quindi quasi sicuramente sarà più lento. – HLGEM

0

utilizziamo l'ID per prevenire i dati di duplicazione e può rendere alcuni processi non complicati (se vogliamo aggiornare o eliminare dati), è più semplice se utilizziamo l'ID.

se non si desidera utilizzare l'ID, è possibile utilizzare altri campi. ma non dimenticare di renderli UNICI. può rendere i vostri dati preventivi dai dati di duplicazione.

un altro modo all'esterno di PRIMARY è UNICO.

0

Vado con tutte le risposte sopra. Direi che un ID è facile da implementare e quando si tratta di indicizzare, Int è sempre preferito rispetto a un varchar. Il tuo professore dovrebbe sapere meglio, perché direbbe di no a Int id è sopra di me!

7

Questo è in genere chiamato surrogate key e ha molti vantaggi. Uno dei quali sta isolando le relazioni del database dai dati dell'applicazione. Maggiori dettagli e gli svantaggi corrispondenti possono essere trovati al link wiki fornito sopra.

0

Perché userid dovrebbe essere univoco (non può essere duplicato) & a volte è indice.

4

Il tuo professore sta facendo la cosa giusta sottolineando che avresti dovuto rendere il nome utente univoco e non annullabile se fosse necessario che i nomi utente fossero unici. Anche l'uid potrebbe essere una chiave, ma a meno che non lo si utilizzi da qualche parte, non è necessario. L'aspetto più importante del design dovrebbe essere quello di implementare la chiave naturale. Quindi sono d'accordo con il commento del tuo professore.

+3

Sono d'accordo con lui sul fatto che dovrebbe avere un vincolo univoco, ma è quasi sempre un errore usare somethign così mutevole come un nome utente come PK. Gli integer sono noti per essere più veloci per i join rispetto ai varchar di queste dimensioni e si aggiornano potenzialmente su milioni di record FK quando le modifiche al nome utente possono portare il sistema a una battuta d'arresto. Qualcuno che insegna design dovrebbe sapere meglio di volere una chiave naturale per qualcosa di così mutevole. – HLGEM

+0

@HLGM: Sono stato su reti e simili da quasi 3 decenni. Non riesco a ricordare il mio nome utente mai cambiato. –

+0

@HLGEM che dice che i nomi utente sono modificabili? – alternative

10

Se avete dimostrato al vostro professore che assegnare un intero arbitrario univoco a ciascun utente è di valore per la vostra applicazione, ovviamente sarebbe sbagliato affermare che è "completamente inutile e non necessario".

Tuttavia, forse hai perso il suo punto. Se ti ha detto che il requisito è "nessun utente può avere lo stesso nome utente" allora non hai soddisfatto quel requisito.

Un sincero ringraziamento per aver pubblicato il tuo DDL SQL, è molto utile ma la maggior parte non si preoccupa di SO.

utilizzo del vostro tavolo, posso fare questo:

INSERT INTO users (username) VALUES (NULL); 
INSERT INTO users (username) VALUES (NULL); 
INSERT INTO users (username) VALUES (NULL); 
INSERT INTO users (username) VALUES (NULL); 
INSERT INTO users (username) VALUES (NULL); 

che si traduce in questo:

SELECT uid, username, passhash, email, rdate 
FROM users; 

uid username passhash email rdate 
1  <NULL>  <NULL>  <NULL> <NULL> 
2  <NULL>  <NULL>  <NULL> <NULL> 
3  <NULL>  <NULL>  <NULL> <NULL> 
4  <NULL>  <NULL>  <NULL> <NULL> 

credo sia il punto il vostro professore stava cercando di fare: senza imporre la chiave naturale username non hai alcuna integrità dei dati.

Se fossi il prof, ti inviterei anche a rimuovere colonne nullable dal tuo progetto.

+0

Grazie, ho dimenticato il vincolo NOT NULL e UNIQUE.Ecco una versione aggiornata: CREATE TABLE users (uid INT NON NULL AUTO_INCREMENT, username VARCHAR (30) NOT NULL, passhash VARCHAR (255) NOT NULL, email VARCHAR (60) NOT NULL, rdate DATA NOT NULL, PRIMARY KEY (uid), UNIQUE (username, email)); – cnandreu

+0

'UNIQUE (username, email)' non fa quello che pensi che faccia. Potresti provare a testare il tuo codice. –

+0

@Catcall: l'ultimo commento era per @CarlosMarx, giusto? – onedaywhen

0

E vuoi memorizzare i tuoi nomi utente in testo chiaro per chiunque voglia rubare? Non prenderei mai in considerazione l'utilizzo di una chiave naturale che potrei voler cifrare un giorno (o volere criptare ora).

+0

Se la sicurezza fosse una preoccupazione, non avresti hash il nome utente piuttosto che crittografarlo? L'hash dovrebbe fare una buona chiave. Se non sei d'accordo, quale chiave naturale useresti per identificare gli utenti in modo univoco? Penso che siamo d'accordo sul fatto che il design originale sia sbagliato ma quali suggerimenti hai per l'OP? – sqlvogel

Problemi correlati