Eccoci di nuovo, la vecchia discussione sorge ancora ...
Dovremmo avere una chiave di business come chiave primaria o preferiremmo avere un ID surrogato (ovvero un'identità di SQL Server) con un vincolo univoco sul campo della chiave di business?
Fornisci esempi o prove a supporto della tua teoria.
Tutti e due. Prendi la tua torta e mangiala.
Ricorda che non c'è nulla di speciale in una chiave primaria, tranne che è etichettata come tale. Non è altro che un vincolo NOT NULL UNIQUE e una tabella può avere più di uno.
Se si utilizza una chiave surrogata, si desidera comunque una chiave aziendale per garantire l'univocità in base alle regole aziendali.
Solo alcuni motivi per usare le chiavi surrogate:
Stabilità: la modifica di una chiave a causa di un'attività o di un'esigenza naturale influirà negativamente sulle tabelle correlate. Le chiavi surrogate raramente, se mai, devono essere modificate perché non vi è alcun significato legato al valore.
Convenzione: ti consente di avere una convenzione standardizzata di denominazione delle colonne della chiave primaria piuttosto che dover pensare a come unire le tabelle con vari nomi per i loro PK.
Velocità: A seconda del valore e del tipo PK, una chiave surrogata di un numero intero può essere più piccola, più veloce da indicizzare e cercare.
Sembra che nessuno abbia ancora detto nulla a sostegno di chiavi non surrogate (esito a dire "naturale"). Quindi ecco qui ...
Uno svantaggio delle chiavi surrogate è che sono prive di significato (citate come vantaggio da alcuni, ma ...). Questo a volte ti costringe a unire molte più tabelle alla tua query di quanto dovrebbe essere realmente necessario. Confrontare:
select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';
contro:
select sum(t.hours)
from timesheets t
join departents d on d.dept_id = t.dept_id
join timesheet_statuses s on s.status_id = t.status_id
join projects p on p.project_id = t.project_id
join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';
A meno che qualcuno non pensi seriamente che sia una buona idea:
select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89
and t.project_id = 1253
and t.task_id = 77;
"Ma" qualcuno dirà "cosa succede quando il codice per MYPROJECT o VALID o HR cambia?" Alla quale la mia risposta sarebbe: "perché dovresti bisogno di cambiarlo?" Queste non sono chiavi "naturali", nel senso che qualche ente esterno legifererà che d'ora in poi "VALID" dovrebbe essere ricodificato come "BUONO". Solo una piccola percentuale di chiavi "naturali" rientra davvero in quella categoria - SSN e codice postale sono i soliti esempi. Utilizzerei sicuramente un tasto numerico insignificante per tabelle come Persona, Indirizzo - ma non per tutto , che per qualche motivo la maggior parte delle persone qui sembrano sostenere.
Vedi anche: la mia risposta a un'altra domanda
La chiave surrogata non avrà MAI un motivo per cambiare. Non posso dire lo stesso delle chiavi naturali. Cognome, e-mail, nubmers ISBN: tutti possono cambiare un giorno.
Le chiavi surrogate (in genere numeri interi) hanno il valore aggiunto di rendere più veloci le relazioni tra tabelle e una maggiore velocità di archiviazione e velocità di aggiornamento (ancora meglio, le chiavi esterne non devono essere aggiornate quando si utilizzano chiavi surrogate, a differenza dei campi chiave aziendale, che cambiano di tanto in tanto).
La chiave primaria di una tabella deve essere utilizzata per identificare in modo univoco la riga, principalmente per scopi di join. Pensa a una tabella Persone: i nomi possono cambiare e non sono garantiti univoci.
Pensa alle aziende: sei una felice azienda Merkin che fa affari con altre società in Merkia. Sei abbastanza intelligente da non usare il nome dell'azienda come chiave primaria, quindi usi l'ID azienda univoco del governo Merkia in tutti i suoi 10 caratteri alfanumerici. Quindi Merkia cambia gli ID dell'azienda perché hanno pensato che sarebbe stata una buona idea. Va bene, usi la funzionalità di aggiornamento in cascata del tuo motore db, per una modifica che non dovrebbe coinvolgerti in primo luogo. Successivamente, la tua attività si espande e ora lavori con un'azienda in Freedonia. L'ID società freedonian ha un massimo di 16 caratteri. È necessario ingrandire la chiave primaria dell'ID azienda (anche i campi della chiave esterna in Ordini, Problemi, Trasferimenti di denaro ecc.), Aggiungendo un campo Paese nella chiave primaria (anche nelle chiavi esterne). Ahia! Guerra civile in Freedonia, è divisa in tre paesi. Il nome del paese del tuo associato dovrebbe essere cambiato in quello nuovo; aggiornamenti in cascata per il salvataggio. A proposito, qual è la tua chiave primaria? (Paese, ID azienda) o (ID azienda, Paese)? Il secondo aiuta ad aderire, il primo evita un altro indice (o forse molti, se vuoi che anche i tuoi ordini vengano raggruppati per paese).
Tutti questi non sono una prova, ma un'indicazione che una chiave surrogata per identificare in modo univoco una riga per tutti gli usi, comprese le operazioni di join, è preferibile a una chiave aziendale.
Odio le chiavi surrogate in generale. Dovrebbero essere utilizzati solo quando non è disponibile una chiave naturale di qualità. È piuttosto assurdo quando ci pensi, pensare che l'aggiunta di dati insignificanti alla tua tabella possa migliorare le cose.
Ecco i miei motivi:
Quando si usano le chiavi naturali, le tabelle sono raggruppate nel modo in cui vengono spesso cercate, rendendo le query più veloci.
Quando si utilizzano chiavi surrogate è necessario aggiungere indici univoci su colonne di chiavi logiche. È ancora necessario impedire dati duplicati logici. Ad esempio, non puoi consentire a due organizzazioni con lo stesso nome nella tabella Organizzazione anche se pk è una colonna ID surrogata.
Quando le chiavi surrogate vengono utilizzate come chiave primaria, è molto meno chiaro quali siano le chiavi primarie naturali. Durante lo sviluppo, vuoi sapere quale set di colonne rende unica la tabella.
In una o più catene di relazioni, le catene chiave logiche. Ad esempio, le organizzazioni hanno molti account e gli account hanno molte fatture. Quindi la chiave logica dell'organizzazione è OrgName. La chiave logica di Account è OrgName, AccountID. La chiave logica di Invoice è OrgName, AccountID, InvoiceNumber.
Quando vengono utilizzate chiavi surrogate, le catene chiave vengono troncate avendo solo una chiave esterna per il genitore immediato. Ad esempio, la tabella delle fatture non ha una colonna OrgName. Ha solo una colonna per AccountID. Se desideri cercare fatture per una determinata organizzazione, dovrai unirti alle tabelle Organizzazione, Account e Fattura. Se si utilizzano chiavi logiche, è possibile eseguire una query direttamente nella tabella Organizzazione.
La memorizzazione dei valori chiave surrogati delle tabelle di ricerca provoca il riempimento di tabelle con numeri interi senza significato. Per visualizzare i dati, è necessario creare viste complesse che si uniscano a tutte le tabelle di ricerca. Una tabella di ricerca deve contenere un set di valori accettabili per una colonna. Non dovrebbe essere codificato memorizzando invece una chiave surrogata intera. Non c'è nulla nelle regole di normalizzazione che suggerisce che è necessario memorizzare un numero intero surrogato invece del valore stesso.
Ho tre diversi libri di database. Nessuno di loro mostra l'uso di chiavi surrogate.
Voglio condividere la mia esperienza con te in questa guerra infinita: D sul dilemma chiave naturale vs surrogato. Penso che sia le chiavi surrogate (quelle generate automaticamente artificiali) sia le chiavi naturali (composte da colonne con significato di dominio) hanno pro e contro . Quindi, a seconda della situazione, potrebbe essere più pertinente scegliere un metodo o l'altro.
Poiché sembra che molte persone presentino chiavi surrogate come la soluzione quasi perfetta e chiavi naturali come la peste, mi concentrerò sugli argomenti dell'altro punto di vista:
Le chiavi surrogate sono:
Usa le chiavi naturali quando è importante farlo e usa le chiavi surrogate quando è meglio usarle.
Spero che questo abbia aiutato qualcuno!
Usa sempre una chiave che non ha significato commerciale. È solo una buona pratica.
EDIT: stavo cercando di trovare un link online, ma non ci sono riuscito. Comunque in 'Patterns of Enterprise Archtecture' [Fowler] ha una buona spiegazione del perché non dovresti usare nient'altro che una chiave senza altro significato che essere una chiave. Si riduce al fatto che dovrebbe avere un lavoro e un solo lavoro.
Le chiavi surrogate sono molto utili se si prevede di utilizzare uno strumento ORM per gestire/generare le classi di dati. Mentre puoi usare chiavi composite con alcuni dei mappatori più avanzati (leggi: ibernazione), aggiunge una certa complessità al tuo codice.
(Naturalmente, i puristi del database sostengono che anche la nozione di chiave surrogata è un abominio.)
Sono un fan dell'uso degli uid per le chiavi surrogate quando è adatto. La principale vittoria con loro è che conosci la chiave in anticipo, ad es. puoi creare un'istanza di una classe con l'ID già impostato e garantito come univoco, mentre con, per esempio, una chiave intera dovrai settare 0 o -1 e aggiornare ad un valore appropriato quando salvi/aggiorni.
Gli UID hanno delle penalità in termini di ricerca e velocità di join, quindi dipende dall'applicazione in questione se sono desiderabili.
L'utilizzo di una chiave surrogata è meglio secondo me in quanto non vi è alcuna possibilità che cambi. Quasi tutto ciò a cui riesco a pensare che potresti usare come chiave naturale potrebbe cambiare (disclaimer: non sempre vero, ma comunemente).
Un esempio potrebbe essere un DB di auto: a prima vista, potresti pensare che la targa possa essere utilizzata come chiave. Ma questi potrebbero essere cambiati in modo che sarebbe una cattiva idea. Non vorrai davvero scoprirlo after rilasciando l'app, quando qualcuno viene da te che vuole sapere perché non può cambiare la sua targa con la sua nuova brillante personalizzata.
Utilizzare sempre una sola colonna, chiave surrogata, se possibile. Ciò rende i join, nonché gli inserti/gli aggiornamenti/le eliminazioni molto più puliti perché sei responsabile solo di tenere traccia di una singola informazione per mantenere il record.
Quindi, se necessario, impila le chiavi della tua azienda come contorni o indici univoci. Ciò manterrà intatta l'integrità dei dati.
La logica aziendale/le chiavi naturali possono cambiare, ma la chiave fisica di una tabella non dovrebbe MAI cambiare.
In uno scenario di datawarehouse credo sia meglio seguire il percorso chiave surrogato. Due motivi:
Questo è uno di quei casi in cui una chiave surrogata è praticamente sempre ha senso. Ci sono casi in cui puoi scegliere ciò che è meglio per il database o ciò che è meglio per il tuo modello di oggetto, ma in entrambi i casi, usare una chiave insignificante o GUID è un'idea migliore. Rende l'indicizzazione più semplice e più veloce ed è un'identità per il tuo oggetto che non cambia.
Ricordiamo che non è buona norma posizionare indici cluster su chiavi surrogate casuali, ad esempio GUID che leggono XY8D7-DFD8S, poiché SQL Server non è in grado di ordinare fisicamente questi dati. Dovresti invece posizionare indici univoci su questi dati, anche se può essere utile eseguire semplicemente il profiler SQL per le operazioni della tabella principale e quindi posizionare tali dati in Ottimizzazione guidata motore di database.
Vedi thread @ http://social.msdn.Microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be
Caso 1: La tabella è una tabella di ricerca con meno di 50 tipi (inserti)
Usa chiavi aziendali/naturali. Per esempio:
Table: JOB with 50 inserts
CODE (primary key) NAME DESCRIPTION
PRG PROGRAMMER A programmer is writing code
MNG MANAGER A manager is doing whatever
CLN CLEANER A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts
foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB
Caso 2: La tua tabella è una tabella con migliaia di inserti
Usa chiavi surrogate/autoincremento. Per esempio:
Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts
foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)
Nel primo caso:
Nel secondo caso:
Le chiavi surrogate possono essere utili quando le informazioni aziendali possono cambiare o essere identiche. I nomi delle imprese non devono essere univoci in tutto il paese, dopo tutto. Supponiamo che tu abbia a che fare con due aziende di nome Smith Electronics, una nel Kansas e una nel Michigan. Puoi distinguerli per indirizzo, ma questo cambierà. Anche lo stato può cambiare; cosa succederebbe se Smith Electronics di Kansas City, Kansas si spostasse attraverso il fiume a Kansas City, Missouri? Non esiste un modo ovvio di mantenere distinte queste attività con informazioni chiave naturali, quindi una chiave surrogata è molto utile.
Pensa alla chiave surrogata come a un numero ISBN. Di solito, identifichi un libro per titolo e autore. Tuttavia, ho due libri intitolati "Pearl Harbor" di H. P. Willmott, e sono sicuramente libri diversi, non solo edizioni diverse. In un caso del genere, potrei fare riferimento all'aspetto dei libri, o il precedente rispetto al successivo, ma è altrettanto bene che ho il codice ISBN su cui ripiegare.
Cavallo per corsi. Per dichiarare il mio pregiudizio; Prima sono uno sviluppatore, quindi mi occupo principalmente di fornire agli utenti un'applicazione funzionante.
Ho lavorato su sistemi con chiavi naturali e ho dovuto dedicare molto tempo ad assicurarmi che le variazioni di valore si propagassero.
Ho lavorato su sistemi con solo chiavi surrogate e l'unico inconveniente è stata la mancanza di dati denormalizzati per il partizionamento.
La maggior parte degli sviluppatori PL/SQL tradizionali con cui ho lavorato non amava le chiavi surrogate a causa del numero di tabelle per join, ma i nostri database di test e produzione non hanno mai sudato; i join extra non hanno influito sulle prestazioni dell'applicazione. Con dialetti di database che non supportano clausole come "X inner join Y on Xa = Yb" o sviluppatori che non usano quella sintassi, i join extra per le chiavi surrogate rendono le query più difficili da leggere e più lunghe da digitare e controlla: vedi il post di @Tony Andrews. Ma se usi un ORM o qualsiasi altro framework di generazione SQL non lo noterai. Anche la digitazione tattile si attenua.
Forse non è completamente pertinente a questo argomento, ma ho mal di testa con le chiavi surrogate. L'analisi Oracle pre-consegnata crea SK generati automaticamente su tutte le sue tabelle dimensionali nel magazzino e memorizza anche quelli sui fatti. Pertanto, ogni volta che devono essere ricaricate (dimensioni) quando vengono aggiunte nuove colonne o devono essere popolate per tutti gli elementi nella dimensione, gli SK assegnati durante l'aggiornamento rendono gli SK non sincronizzati con i valori originali memorizzati nel fatto, forzando una ricarica completa di tutte le tabelle dei fatti che vi si uniscono. Preferirei che anche se la SK fosse un numero insignificante, ci sarebbe un modo in cui non potrebbe cambiare per i record originali/vecchi. Come molti sanno, il pronto intervento raramente soddisfa le esigenze di un'organizzazione e dobbiamo personalizzare costantemente. Ora disponiamo di dati per un valore di 3 anni nel nostro magazzino e le ricariche complete dai sistemi finanziari Oracle sono molto grandi. Quindi, nel mio caso, non vengono generati dall'immissione dei dati, ma aggiunti in un magazzino per aiutare a riportare le prestazioni. Ho capito, ma i nostri cambiano ed è un incubo.
Nel caso del database point in time è meglio avere una combinazione di chiavi surrogate e chiavi naturali. per esempio. devi tenere traccia delle informazioni di un socio per un club. Alcuni attributi di un membro non cambiano mai. ad es. Data di nascita ma il nome può cambiare. Quindi crea una tabella Member con una chiave surrogata member_id e disponi di una colonna per DOB. Crea un'altra tabella chiamata nome persona e disponi di colonne per member_id, member_fname, member_lname, date_updated. In questa tabella la chiave naturale sarebbe member_id + date_updated.