Quando una chiave primaria deve essere dichiarata non cluster?


169

Durante la creazione di un database di test per un'altra domanda che ho posto in precedenza, mi sono ricordato che una chiave primaria poteva essere dichiarata NONCLUSTERED

Quando useresti una NONCLUSTEREDchiave primaria anziché una CLUSTEREDchiave primaria?

Grazie in anticipo

Risposte:


188

La domanda non è "quando dovrebbe essere il PK NC", ma invece si dovrebbe chiedere "qual è la chiave corretta per l'indice cluster"?

E la risposta dipende davvero da come si interrogano i dati . L'indice cluster presenta un vantaggio rispetto a tutti gli altri indici: poiché include sempre tutte le colonne, copre sempre. Pertanto, le query che possono sfruttare l'indice cluster non devono certamente utilizzare le ricerche per soddisfare alcune delle colonne e / o predicati proiettati.

Un altro pezzo del puzzle è come si può usare un indice ? Esistono tre schemi tipici:

  • sonde, quando nell'indice viene cercato un singolo valore chiave
  • scansioni dell'intervallo, quando viene recuperato un intervallo di valori chiave
  • ordina per requisiti, quando un indice può soddisfare un ordine senza richiedere un ordinamento stop-and-go

Pertanto, se si analizza il carico previsto (le query) e si scopre che un gran numero di query utilizzerebbe un determinato indice perché utilizzano un determinato modello di accesso che beneficia di un indice, ha senso proporre tale indice come indice cluster.

Ancora un altro fattore è che la chiave di indice cluster è la chiave di ricerca utilizzata da tutti gli indici non cluster e quindi una chiave di indice cluster ampia crea un effetto a catena e allarga tutti gli indici non cluster e indici ampi significano più pagine, più I / O , più memoria, meno bontà.

Un buon indice cluster è stabile , non cambia durante il ciclo di vita dell'entità, poiché una modifica dei valori della chiave dell'indice cluster indica che la riga deve essere eliminata e reinserita.

E un buon indice cluster cresce in modo non casuale (ogni valore della chiave appena inserito è maggiore del valore precedente) in modo da evitare la divisione delle pagine e la frammentazione (senza fare casini con FILLFACTORs).

Quindi, ora che sappiamo cos'è una buona chiave di indice cluster, la chiave primaria (che è una proprietà logica di modellazione dei dati) soddisfa i requisiti? Se sì, allora il PK dovrebbe essere raggruppato. In caso contrario, il PK deve essere non cluster.

Per fare un esempio, considera una tabella dei fatti di vendita. Ogni voce ha un ID che è la chiave primaria. Ma la stragrande maggioranza delle query richiede dati tra una data e un'altra data, quindi la migliore chiave di indice cluster sarebbe la data di vendita , non l' ID . Un altro esempio di avere un indice cluster diverso dalla chiave primaria è una chiave di selettività molto bassa, come una 'categoria' o uno 'stato', una chiave con solo pochissimi valori distinti. Avere una chiave indice cluster con questa chiave a bassa selettività come chiave all'estrema sinistra, ad esempio (state, id), spesso ha senso a causa delle scansioni di intervalli che cercano tutte le voci in un particolare "stato".

Un'ultima nota sulla possibilità di una chiave primaria non cluster su un heap (ovvero non esiste alcun indice cluster). Questo può essere uno scenario valido, il motivo tipico è quando le prestazioni dell'inserimento di massa sono critiche, poiché gli heap hanno un throughput di inserimento di massa significativamente migliore rispetto agli indici cluster.


1
Che cosa significa "ordina per requisiti, quando un indice può soddisfare un ordine senza richiedere un ordinamento stop-and-go"?
Mike Sherrill 'Cat Recall'

2
@RemusRusanu. +1 Risposta molto utile. Una domanda sull'esempio (state, id). In questo esempio il requisito "un buon indice cluster cresce in modo non casuale" non sarà soddisfatto, vero? Quindi possiamo considerarlo come un buon indice cluster?
LCJ,

26

Il motivo di base per utilizzare gli indici cluster è indicato su Wikipedia :

Il clustering altera il blocco di dati in un determinato ordine distinto in modo che corrisponda all'indice, con conseguente memorizzazione dei dati di riga. Pertanto, è possibile creare un solo indice cluster su una determinata tabella del database. Gli indici cluster possono aumentare notevolmente la velocità complessiva di recupero, ma in genere solo quando si accede ai dati in sequenza nello stesso ordine inverso dell'indice cluster o quando viene selezionato un intervallo di elementi.

Supponiamo che io abbia una tabella di persone e che queste persone abbiano una colonna Paese e una chiave primaria univoca. È una tabella demografica, quindi queste sono le uniche cose a cui tengo; quale Paese e quante persone uniche sono legate a quel Paese.

Sono quindi sempre e solo in grado di SELEZIONARE DOVE O ORDINARE dalla colonna Paese; un indice cluster sulla chiave primaria non mi fa nulla di buono, non accedo a questi dati da PK, sto accedendo da quest'altra colonna. Dal momento che posso avere solo un indice cluster su una tabella, dichiarare il mio PK come Clustered mi impedirebbe di utilizzare un Indice cluster su Paese.

Inoltre, ecco un buon articolo sugli indici cluster e non cluster , risulta che gli indici cluster hanno causato problemi di prestazioni di inserimento in SQL Server 6.5 (che almeno si spera non sia rilevante per la maggior parte di noi qui).

Se si inserisce un indice cluster in una colonna IDENTITÀ, tutti gli inserimenti verranno eseguiti nell'ultima pagina della tabella e tale pagina verrà bloccata per la durata di ciascuna IDENTITÀ. Non è un grosso problema ... a meno che tu non abbia 5000 persone che vogliono l'ultima pagina. Quindi hai molte discussioni per quella pagina

Si noti che questo non è il caso nelle versioni successive.


3
FIY, hai menzionato SQL Server 6.5: dba.stackexchange.com/questions/1584/…
gbn

15

Se la tua chiave primaria è di UNIQUEIDENTIFIER, assicurati di specificare che è NONCLUSTERED. Se lo rendi raggruppato, ogni inserimento dovrà fare un mucchio di riordino dei record per inserire la nuova riga nella posizione corretta. Questo migliorerà le prestazioni.


1
Mentre provo a evitare gli UUID per le chiavi raggruppate, credo che il ragionamento sopra potrebbe essere incompleto. Il server SQL non rimpasto necessariamente le righe per inserire a nella posizione corretta (se si intende "tra il valore più basso e più alto"). Considera un inserto nel mezzo di una tabella di trilioni di righe. È necessaria un'ulteriore direzione indiretta, che potrebbe essere ciò che intendevi. Un sequenziale UNIQUEIDENTIFIERtipo esiste anche, e ha la stessa probabilità di generare chiavi univoche, anche se soffre ancora una taglia 128.
Charles Burns,

8

Un esempio molto comune:

  • Customertavolo con CustomerIDasCLUSTERED PRIMARY KEY
  • Ordina la tabella con OrderID (PK), CustomerID, OrderDatee alcune altre colonne
  • OrderPositions con OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • devi indicizzare le tabelle degli ordini

Naturalmente "dipende" è - come quasi sempre - la risposta corretta, ma la maggior parte delle applicazioni (non BI-Reports) funzionerà in base al cliente (ad es. Accedi come cliente 278 nel sito Web e fai clic su "I miei ordini" o l'impiegato elenca tutti gli ordini per il cliente 4569 o la routine della fattura sommerà tutti gli ordini per il cliente 137).

In questo caso non avrebbe molto senso raggruppare la tabella in base a OrderID. Sì, avrai domande su come SELECT ... WHERE OrderId = ?elencare i dettagli dell'ordine, ma questo sarebbe solitamente un indice breve ed economico (3 letture).

D'altra parte, se si desidera raggruppare la Ordertabella in base a CustomerID, non dovrebbe eseguire più ricerche di chiavi ogni volta che si esegue una query per la tabella CustomerId = ?.

Il CLUSTERED INDEXdovrebbe essere sempre UNIQUE, altrimenti SQL Server aggiungerebbe un (= inutilizzabile) colonna INT invisibile UNIQUIFIERper garantire l'uniquiness - e sarebbe molto più senso per aggiungere i dati reali (utilizzabili) poi alcuni casuale (a seconda dell'ordine di inserimento) roba.

Poiché un cliente effettuerà (si spera) più di un ordine, dovremmo aggiungere OrderIDo (se di solito si ordina per questo) il OrderDate(se si tratta di un datetime - altrimenti il ​​cliente sarebbe limitato a un ordine al giorno) a l' CLUSTERED INDEXe finire con:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

Le stesse regole si applicano alla OrderPositionstabella. Di solito la maggior parte delle query elencherà tutte le posizioni per un ordine specifico, quindi è necessario creare il PK con OrderPositionIDas NONCLUSTEREDe a UNIQUE CLUSTERED INDEXon OrderId, OrderPositionID.

A proposito: è corretto che la Customertabella sia raggruppata dal suo PK (il CustomerID, perché è una "tabella di livello superiore" e - in un'applicazione tipica - sarà per lo più interrogata dal suo ID cliente.

Le tabelle di ricerca pure come ad esempio Genderso InvoiceTypeso PaymentTypesono un altro esempio di tabelle che dovrebbero essere raggruppate dal suo PK (perché di solito le unirai a esse GenderId, InvoiceTypeIdo PaymentTypeId).


2

Quando un indice cluster è considerato più vantaggioso per il sistema complessivo rispetto a un PK cluster utilizzando una certa misura delle prestazioni. Su una tabella può esserci solo un indice cluster.

Esempi di misure delle prestazioni sono il tempo di query singolo (velocità), l'integrazione dei tempi di query totali rispetto alla tabella (efficienza) e la necessità di aggiungere molte colonne di inclusione a un indice non cluster molto ampio al fine di ottenere prestazioni simili a quelle del cluster (dimensione ).

Ciò può accadere quando i dati vengono generalmente recuperati utilizzando un indice che non è univoco, contiene valori null (non consentiti in un PK) o il PK è stato aggiunto per un motivo secondario (come la replica o l'identificazione del record della pista di controllo).

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.