Quali sono i compromessi per l'incremento degli ID rispetto alle chiavi full-text per la progettazione di chiavi esterne?


8

In molti progetti di database relazionali ci sono campi a cui si fa riferimento in altre tabelle.

Ad esempio, prendere in considerazione una tabella utente con un nome utente univoco e una seconda tabella che memorizza i dati dell'indirizzo.

Un possibile layout, che direi è l'approccio comune, poiché ho osservato nella maggior parte dei software, è utilizzare ID di incremento automatico come questo:

Table users
===========
userId int primary auto_increment
userName varchar unique

Table adressdata
==========
userId int references users.userId
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userId,adress_type))

Questo è il modo in cui lo facevo e come l'ho visto nella maggior parte dei casi.

Un altro modo sarebbe:

Table users
===========
userName varchar primary

Table adressdata
==========
userName varchar references users.userName
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userName,adress_type))

Qui memorizziamo il nome utente completo anche nella tabella adressdata.

Per me questo ha i seguenti vantaggi:

  • È possibile selezionare il nome utente immediatamente dalla tabella senza la necessità di unirlo a un'altra tabella. In questo esempio questo è da un punto di vista dell'applicazione probabilmente non così rilevante, ma è solo un esempio.

  • Potrebbe essere più semplice ridimensionare il database in un ambiente di replica master-master, poiché non vi sono conflitti per l'incremento automatico.

Ma anche gli svantaggi:

  • I requisiti di spazio per l'indice e i dati (ma probabilmente più rilevante sarà l'indice) sul campo nella seconda tabella sono più elevati.
  • Una modifica del nome utente dovrebbe propagarsi a tutte le tabelle, il che richiede più risorse rispetto alla semplice modifica in una tabella e lascia gli ID così come sono.

A mio avviso, è molto più semplice lavorare con i campi di testo e non usare gli ID di incremento, e i compromessi sono minimi e nella maggior parte delle applicazioni non rilevanti.

Naturalmente alcuni oggetti SONO identificati con un numero crescente per loro natura (ad esempio i post dei forum dovrebbero ricevere un ID incrementale perché probabilmente non esiste un altro campo univoco come titolo o simili).

Ma prima di iniziare a progettare i layout del mio database in un modo completamente diverso, vorrei sapere se ci sono cose a cui non ho pensato.

  • Ci sono delle migliori pratiche?

  • Ci sono pro / contro che non pensavo e il cui effetto potrebbe sorgere in un momento successivo?

  • Come progettate personalmente i database relativi ai punti precedenti e perché?

Risposte:


3

Suggerirei di utilizzare l'id e non il nome utente, perché se inizi a utilizzare il nome utente come colonna di join in più tabelle, devi ricordarti di aggiornarli tutti.

La chiave esterna per la userstabella diventa la chiave primaria della addressdatatabella e la chiave primaria deve rimanere stabile. È buona norma non modificare i campi chiave primaria. Una chiave primaria deve esistere quando viene creato il record e deve rimanere invariata per l'intera durata del record.

Se desideri ulteriori approfondimenti Il grande dibattito sulla chiave primaria è un ottimo articolo.


2

Sono fortemente nel campo "non usare le chiavi naturali". Questo perché ho visto quanto sia difficile il sistema quando vengono aggiornati e praticamente tutte le chiavi naturali che coinvolgono i nomi di anykind vengono aggiornate.

I database sono ottimizzati per utilizzare i join. Sì, è possibile salvare alcuni join utilizzando le chiavi naturali ma il risultato è positivo quando è necessario aggiornare 1.000.000 di record perché un gruppo di chiavi naturali modificato (o anche a seconda di ciò che sta accadendo) può essere un enorme logjam.

Vorrei usare le chiavi naturali solo in due condizioni:

  1. se la chiave è abbastanza garantita per non cambiare (pensate ai numeri VIN dell'automobile) e
  2. se non verrà mai riutilizzato (anche cose uniche come numeri di telefono ed e-mail non sono candidati per un PK perché vengono riutilizzati quando qualcuno smette di usarli).

E naturalmente troppe chiavi naturali che dovrebbero essere uniche non lo sono. Se sei preoccupato per la replica, puoi utilizzare i GUID.


1

L'articolo di Wikipedia sulla chiave surrogata ha alcuni bit interessanti sparsi:

  • "Gli attributi che identificano in modo univoco un'entità potrebbero cambiare, il che potrebbe invalidare l'idoneità delle chiavi composte naturali. " Ad esempio, restrizioni successive sui nomi utente potrebbero invalidare le chiavi esistenti quando si utilizza la chiave naturale, user namementre ciò non influirà su una chiave sintetica.
  • "Le chiavi surrogate non cambiano mentre esiste la riga. " Pertanto, non è necessario (manualmente o automaticamente) mettere in cascata le modifiche delle chiavi alle tabelle dei riferimenti.
  • " I valori delle chiavi surrogate generate non hanno alcuna relazione con il significato reale dei dati contenuti in una riga. " Ciò può rendere difficile l'auditing.

Credo che il lettore attento possa trovare ulteriori punti da considerare.


Buona risposta. Molte chiavi naturali hanno la tendenza ai cambiamenti. Ciò li rende inadatti per le chiavi a cui si può fare riferimento come chiave esterna. Esistono molti motivi per cui è opportuno modificare l'ID utente di un utente.
BillThor,

1

Pubblicherò dalla mia esperienza che probabilmente sarà molto diversa da ciò che i vari DBA potrebbero suggerire. Sono principalmente orientato verso un mix di prestazioni e manutenibilità durante la progettazione di database per vari progetti.

Non userei mai e poi mai una chiave naturale per la chiave primaria. Soprattutto se uso MySQL / InnoDB. Non ho ancora visto alcun vantaggio nell'uso di una chiave naturale, di solito ciò che vedo sono conseguenze sulle prestazioni se non nulla. Ho osato "mai, mai" solo perché le chiavi naturali erano utilizzate per creare maiali delle prestazioni per i miei progetti. Surrogate (numero intero) è sempre stata una scelta migliore. Alcuni potrebbero non essere d'accordo, ma viviamo in un mondo in cui la performance ha un ruolo nella teoria.

Quando si tratta di JOIN, non cerco di evitarli a tutti i costi, ma tendo a ottimizzarli. Cerco di abusare il più possibile dell'indice cluster di InnoDB (chiave primaria). Se i JOIN vengono eseguiti tramite PK, sono estremamente veloci. Tendo anche a evitare gli FK dove non hanno senso. Onestamente, non mi interesserebbe così tanto l'integrità dei dati quando si tratta di collegare gli utenti e le loro informazioni di indirizzo. Lo imporrei quando si collegano le fatture agli articoli agli utenti. L'uso eccessivo di FK è un problema eccessivo e un incubo da mantenere dopo aver fatto riferimento a tutto, pensando che sia un ottimo design per mantenere le relazioni ovunque. Ad un certo punto, le cose devono cambiare e quando MySQL inizia a lamentarsi costantemente dell'errore 150, vuoi solo andare a casa.

Hai anche menzionato la replica ed evitare gli scontri a causa della natura di auto_increments. Avevo un progetto in cui avevamo una quantità di database che memorizzavano le informazioni sulle vendite dei prodotti, la quantità di database era variabile. Ogni giorno i database venivano replicati in un database "master" che usavamo per eseguire i report. Il modo in cui ho evitato gli scontri PK è stato quello di creare una chiave primaria composta da una parte auto_increment e un'altra parte INT che indicava la posizione da cui proveniva il record. In questo modo ho potuto rintracciare la provenienza delle cose e non ho perso nulla (i prodotti avevano lo stesso ID, solo l'identificatore di posizione è stato modificato).

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.