Selezione indice cluster - PK o FK?


11

Ho una tabella di SQL Server 2014 simile al seguente:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Alcune persone del mio team hanno suggerito che l'indice cluster dovrebbe essere attivo OrderId, ma penso che il CustomerId+ OrderIdsarebbe una scelta migliore per i seguenti motivi:

  • Quasi tutte le query cercheranno WHERE CustomerId = @param, noOrderId
  • CustomerIdè una chiave esterna per la Customertabella, quindi avere un indice cluster con CustomerIddovrebbe accelerare i join
  • Sebbene CustomerIdnon sia univoco, avere la OrderIdcolonna aggiuntiva specificata nell'indice garantirà l'univocità (possiamo usare la UNIQUEparola chiave durante la creazione dell'indice cluster su quelle 2 colonne, per evitare il sovraccarico di non avere unicità)
  • Una volta inseriti i dati, il CustomerIde OrderIdnon cambiano mai, quindi queste righe non si muoveranno dopo la scrittura iniziale.
  • L'accesso ai dati avviene tramite un ORM che richiede tutte le colonne per impostazione predefinita, quindi quando CustomerIdarriva una query basata su , l'indice cluster sarà in grado di fornire tutte le colonne senza alcun lavoro aggiuntivo.

L' approccio CustomerIde OrderIdsuona come l'opzione migliore data quanto sopra? Oppure, è di OrderIdper sé migliore, dal momento che è un'unica colonna che garantisce l'unicità da sola?

Attualmente, la tabella ha un indice cluster attivo OrderIde un indice non cluster attivo CustomerId, ma non copre, quindi poiché stiamo usando un ORM e sono richieste tutte le colonne, è un lavoro extra per recuperarli. Quindi, con questo post, sto provando a considerare il miglioramento delle prestazioni con un CI migliore.

L'attività sul nostro DB è di circa l'85% in lettura e il 15% in scrittura.

Risposte:


5

Risposta wiki della community :

Penso che una chiave di indice cluster composita con CustomerID come prima colonna sarà la migliore poiché è nella WHEREclausola di quasi tutte le query.

Potrebbero esserci più divisioni rispetto a una chiave incrementale (o più probabile densità di pagina non ottimale per un certo periodo se gestisci e mantieni il fattore di riempimento per evitare divisioni "errate"). Tuttavia, il miglioramento complessivo delle prestazioni per le richieste dei clienti è sostanziale, poiché la ricerca chiave viene evitata.

OrderID o OrderDate potrebbero essere i migliori per la seconda colonna a seconda delle domande più critiche.

Ad esempio, se i clienti visualizzano un elenco cronologico degli ordini recenti dopo aver effettuato l'accesso a un sito Web, OrderDate dovrebbe essere il prossimo, per ottimizzare ORDER BY OrderDate DESC.

Se si sceglie OrderID come indice cluster, con un indice non cluster su CustomerID , si otterranno comunque divisioni e frammentazione, proprio nell'indice non cluster.


3

Se questa tabella è molto intensa in termini di scrittura (ad esempio INSERTsi verificano molte più dichiarazioni anziché SELECTdichiarazioni contrarie), non sarò d'accordo con la risposta della wiki .

La scelta di CustomerID come prima colonna di una chiave cluster composta genererà molte suddivisioni a metà pagina . Spero che abbiate molti clienti esistenti e anche molti nuovi clienti per tutto il tempo. Poiché i clienti effettuano (si spera) più ordini man mano che la tua attività continua a crescere, questo approccio mostrerà una buona quantità di divisioni a metà pagina che uccideranno le prestazioni non solo nelle scritture, ma anche in quanto i tuoi indici saranno entrambi fortemente frammentati e probabilmente contengono maggiori quantità di spazio bianco (il che significa memoria e memoria sprecata).

Se ritieni che CustomerID debba essere una colonna principale di un indice cluster composito, puoi ridurre l'impatto delle divisioni a metà pagina regolando FILLFACTORtutti gli indici per questa tabella. Ciò ridurrà la quantità di divisioni a metà pagina aumentando la dimensione della tabella / indice. Se vuoi seguire questa strada, suggerirei di provare con un valore di 80 e ridurre se l' analisi rivela che le divisioni a metà pagina stanno ancora uccidendo le prestazioni.

Il mio consiglio è di usare OrderId. OrderID dovrebbe naturalmente essere sequenziale e generare più divisioni della pagina finale che sono buone e attese con la crescita della tabella. Inoltre, questo approccio funzionerà meglio con il partizionamento delle tabelle se si sceglie di utilizzare la colonna OrderDate come chiave di partizione. Per quanto riguarda le query che utilizzano costantemente il campo CustomerID, creare un indice non cluster per gestire tali query. Questo indice dovrebbe essere definito con il corretto FILLFACTORin quanto soffrirà di spaccature a metà pagina che ho menzionato sopra, anche se questi non saranno così male in generale in contrasto con se gli scissi si verificassero contro l'indice cluster.

L'attività sul nostro DB è di circa l'85% in lettura e il 15% in scrittura.

CustomerID+ OrderID(e specificando un fattore di riempimento per consentire la crescita senza divisioni) è probabilmente meglio se tale valutazione è vera. Basta fare sicuro che la valutazione è preciso. Test test test.


1
Si noti che l'inserimento di un ordine per l'ultimo (o unico) cliente in una pagina non è una "divisione a metà pagina". Pertanto, se gli ordini per cliente sono elevati o la larghezza della riga è grande, un numero inferiore di inserti ordine richiederà "suddivisioni a metà pagina".
David Browne - Microsoft,
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.