Una cosa da considerare è che una chiave primaria e un indice cluster non sono la stessa cosa. Una chiave primaria è un vincolo e si occupa delle regole in base alle quali i dati vivono (ovvero l'integrità dei dati); non ha nulla a che fare con l'efficienza / le prestazioni. Una chiave primaria richiede che le colonne chiave siano univoche (in combinazione) e NON NULL (singolarmente). Un PK viene applicato tramite un indice univoco, sebbene possa essere cluster o non cluster.
Un indice cluster è un mezzo per ordinare fisicamente (cioè su disco) i dati nella tabella e gestire le prestazioni; non ha nulla a che fare con l'integrità dei dati. Un indice cluster puòrichiedono che le colonne chiave siano univoche (in combinazione), ma non è necessario. Tuttavia, poiché l'indice cluster è l'ordine fisico dei dati, è necessario identificare in modo univoco ogni riga, qualunque cosa accada. Pertanto, se non lo si imposta per richiedere l'univocità, creerà la propria unicità tramite una colonna "uniquifier" a 4 byte nascosta. Quella colonna è sempre presente negli indici cluster non univoci, ma non occupa spazio quando i campi chiave sono univoci (in combinazione). Per vedere in prima persona come funziona questa colonna "uniquifier" (sia nell'indice cluster sia l'effetto sugli indici non cluster), dai un'occhiata a questo script di test che ho pubblicato su PasteBin: script T-SQL per testare le dimensioni di Uniquifier .
Quindi, la domanda principale di:
sarebbe più efficiente aggiungere un id
campo di incremento automatico e usarlo insieme company_id
come chiave primaria, o aggiungerebbe un sovraccarico non necessario
sta combinando questi due concetti, quindi devono essere affrontati separatamente, anche se c'è sicuramente qualche sovrapposizione.
Dovrebbe IDENTITY
essere aggiunta una colonna o sarebbe un sovraccarico non necessario?
Se aggiungi una INT IDENTITY
colonna e la usi per creare un PK, supponendo che sarebbe un PK in cluster, che aggiunge 4 byte a ogni riga. Questa colonna è visibile e utilizzabile nelle query. Si potrebbe essere aggiunto ad altri tavoli come chiave esterna, anche se in questo caso particolare che non accadrà.
Se non aggiungi la INT IDENTITY
colonna, non puoi creare un PK su questa tabella. Tuttavia, è ancora possibile creare un indice cluster sulla tabella purché non si utilizzi l' UNIQUE
opzione. In questo caso, SQL Server aggiungerà una colonna nascosta chiamata "uniquifier" che si comporta come descritto sopra. Poiché la colonna è nascosta, non può essere utilizzata nelle query o come riferimento per le chiavi esterne.
Per quanto riguarda l'efficienza, queste opzioni sono all'incirca le stesse. Sì, ci sarà un po ' meno spazio occupato dall'indice cluster non univoco a causa di alcune righe (quelle con i valori chiave univoci iniziali) che occupano 0 byte mentre tutte le righe in IDENTITY
/ PK occuperanno i 4 byte. Ma non ci sarà abbastanza delle righe a 0 byte (specialmente con la piccola quantità di righe previste) per notare mai una differenza, per non parlare della comodità di poter usare la ID
colonna nelle query.
INT IDENTITY Colonna o hash della org_path
colonna calcolata persistente?
Dato che non cercherai le righe in base ai org_path
valori, non ha senso aggiungere l'overhead della colonna calcolata persistente oltre a dover calcolare l'hash nelle query per corrispondere alla colonna calcolata (questo era il mio suggerimento originale, disponibile nella cronologia delle revisioni qui , basato sulla formulazione iniziale / dettagli della domanda). In questo caso particolare, la INT IDENTITY
colonna "ID" è probabilmente la migliore.
Ordine colonna chiave
Dato che la ID
colonna verrà raramente, se mai, utilizzata nelle query e dato che i due casi d'uso principali devono ottenere "tutte le righe" o "tutte le righe per un dato company_id
", creerei il PK company_id, id
. E poiché ciò significa che le righe non vengono inserite in sequenza, specificherei un valore FILLFACTOR
di 90. Dovrai inoltre assicurarti di eseguire regolarmente la manutenzione dell'indice per ridurre la frammentazione.
Seconda domanda
il fatto che company_id sia la chiave primaria in un'altra tabella ha qualche effetto qui
No.
grilletto
Poiché i org_path
valori all'interno di a company_id
sono univoci, è comunque necessario creare un trigger INSERT, UPDATE
per imporlo. Nel trigger, eseguire un IF EXISTS
con una query che probabilmente esegue un COUNT(*)
e GROUP BY company_id, org_path
. Se viene trovato qualcosa, emettere a ROLLBACK
per annullare l'operazione DML e quindi RAISERROR
dire che ci sono duplicati.
confronto
Nella mia risposta iniziale (basata sulla formulazione originale / dettagli sparsi della domanda, e disponibile nella cronologia delle revisioni qui ), avevo suggerito possibilmente di usare una raccolta binaria (cioè _BIN2
). Ora che abbiamo una visione di cosa sia esattamente org_path
, non consiglierei di usare una raccolta binaria. Dal momento che non ci saranno segni diacritici, è cosa vuole fare uso di equivalenze linguistiche.