Clustered vs Non-Cluster


98

La mia conoscenza di livello inferiore di SQL (Server 2008) è limitata e ora viene messa alla prova dai nostri DBA. Lascia che ti spieghi (ho menzionato affermazioni ovvie nella speranza di avere ragione, ma se vedi qualcosa che non va, per favore dimmelo) lo scenario:

Abbiamo un tavolo che contiene le "ordinanze del tribunale" per le persone. Quando ho creato la tabella, (Name: CourtOrder), l'ho creata in questo modo:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Ho quindi applicato un indice non cluster alla chiave primaria (per efficienza). Le mie ragioni sono che si tratta di un campo unico (chiave primaria) e dovrebbe essere indicizzato, principalmente per scopi di selezione, come spessoSelect from table where primary key = ...

Ho quindi applicato un indice CLUSTER su PersonId. Il motivo era raggruppare fisicamente gli ordini per una determinata persona, poiché la stragrande maggioranza del lavoro consiste nel ricevere ordini per una persona. Così,select from mytable where personId = ...

Sono stato tirato su su questo ora. Mi è stato detto che dovremmo mettere l'indice cluster sulla chiave primaria e l'indice normale su personId. Mi sembra molto strano. Prima di tutto, perché dovresti inserire un indice cluster su una colonna univoca? cos'è il clustering? Sicuramente è uno spreco dell'indice cluster? Avrei creduto che un indice normale sarebbe stato utilizzato su una colonna unica. Inoltre, raggruppare l'indice significherebbe che non possiamo raggruppare una colonna diversa (una per tabella, giusto?).

Il motivo per cui mi è stato detto che ho commesso un errore è che credono che l'inserimento di un indice cluster su PersonId rallenterebbe gli inserimenti. Per il guadagno del 5% in velocità di una selezione, avremmo una riduzione del 95% della velocità su inserimenti e aggiornamenti. È corretto e valido?

Dicono che, poiché raggruppiamo il personId, SQL Server deve riorganizzare i dati ogni volta che inseriamo o apportiamo una modifica a PersonId.

Allora ho chiesto, perché SQL dovrebbe avere il concetto di un INDICE A CLUSTER, se è così lento? È lento come dicono? Come devo impostare i miei indici per ottenere prestazioni ottimali? Avrei pensato che SELECT fosse usato più di INSERT ... ma dicono che abbiamo problemi di blocco su INSERTS ...

Spero che qualcuno possa aiutarmi.


Risposte:


117

La distinzione tra un indice cluster e non cluster è che l'indice cluster determina l'ordine fisico delle righe nel database . In altre parole, applicare l'indice cluster a PersonIdsignifica che le righe verranno ordinate fisicamente PersonIdnella tabella, consentendo una ricerca nell'indice su questo per andare direttamente alla riga (piuttosto che a un indice non cluster, che ti indirizzerebbe alle righe posizione, aggiungendo un passaggio aggiuntivo).

Detto questo, è insolito che la chiave primaria non sia l'indice cluster, ma non è inaudito. Il problema con il tuo scenario è in realtà l'opposto di quello che stai supponendo: vuoi valori univoci in un indice cluster, non duplicati. Poiché l'indice cluster determina l'ordine fisico della riga, se l'indice si trova su una colonna non univoca, il server deve aggiungere un valore di sfondo alle righe che hanno un valore chiave duplicato (nel tuo caso, qualsiasi riga con lo stesso PersonId) in modo che il valore combinato (chiave + valore dello sfondo) sia univoco.

L'unica cosa che suggerirei è di non utilizzare una chiave surrogata (la tua CourtOrderId) colonna come chiave primaria, ma invece di utilizzare una chiave primaria composta di PersonIde qualche altra colonna o insieme di colonne di identificazione univoca. Se ciò non è possibile (o non pratico), tuttavia, attiva l'indice cluster CourtOrderId.


Grazie Adam. Quindi, quando sarebbe utile un indice cluster? Ho pensato che il vantaggio fosse l'indice cluster era di raggruppare i dati, per i momenti in cui, ad esempio, la maggior parte delle query sono su un PersonID ... quindi i dati sarebbero raggruppati.
Craig

3
E ' non è fisicamente allineati secondo PersonId. È ordinato logicamente per PersonId, qualsiasi discrepanza tra ordine logico e fisico è il grado di frammentazione logica.
Martin Smith,

1
@cdotlister Il vantaggio di un indice è ordinare i dati, non raggrupparli (il che implica la duplicazione dei dati all'interno dell'indice). Mentre la distinzione potrebbe sembrare semantica, nel caso degli indici cluster non lo è. Se possibile, l'indice cluster dovrebbe essere su qualcosa che identifica in modo univoco la riga e (idealmente) è anche la colonna o l'insieme di colonne più comunemente interrogati. Questo è il motivo per cui di solito si trova sulla chiave primaria.
Adam Robinson

1
@CyberSluethOmega: non lo so; la tua domanda non contiene informazioni sufficienti per consentirmi di prendere una decisione. Vorrei un indice cluster su un insieme di colonne in cui le righe sarebbero state aggiunte o eliminate frequentemente oltre che alla fine della tabella ? No. Ma non sono davvero sicuro del motivo per cui lo chiedi o del voto negativo.
Adam Robinson

1
@CyberSluethOmega: Internet può far sembrare i commenti difensivi o freddi quando non sono intesi in questo modo. Hai affermato che ho detto che non conoscevo circostanze in cui rendere l'indice cluster qualcosa di diverso dalla chiave primaria, quando in realtà non ho detto nulla del genere. In realtà, quello che ho detto è stata "questo è insolito ..., ma non senza precedenti", il che significa che io non conosco casi in cui questo viene fatto.
Adam Robinson

14

Non sono affatto un esperto di SQL ... quindi prendi questo come punto di vista di uno sviluppatore piuttosto che come un punto di vista DBA ..

Gli inserimenti su indici cluster (ordinati fisicamente) che non sono in ordine sequenziale causano lavoro aggiuntivo per inserimenti / aggiornamenti. Inoltre, se si verificano molti inserimenti contemporaneamente e si verificano tutti nella stessa posizione, si finisce con la contesa. Le tue prestazioni specifiche variano in base ai tuoi dati e al modo in cui accedi. La regola generale è costruire il tuo indice cluster sul valore stretto più unico nella tua tabella (in genere il PK)

Presumo che il tuo PersonId non cambierà, quindi gli aggiornamenti non entrano in gioco qui. Ma considera un'istantanea di alcune righe con PersonId di 1 2 3 3 4 5 6 7 8 8

Ora inserisci 20 nuove righe per PersonId di 3. Innanzitutto, poiché questa non è una chiave univoca, il server aggiunge alcuni byte extra al tuo valore (dietro le quinte) per renderlo unico (che aggiunge anche spazio extra) e poi la posizione in cui questi risiederanno deve essere modificato. Confrontalo con l'inserimento di un PK auto-incrementante in cui gli inserimenti avvengono alla fine. La spiegazione non tecnica verrebbe probabilmente ridotta a questo: c'è meno lavoro di `` sfogliare le foglie '' da fare se sta progredendo naturalmente con valori più alti alla fine della tabella rispetto alla rilavorazione della posizione degli elementi esistenti in quella posizione durante l'inserimento degli elementi.

Ora, se hai problemi con gli inserti, probabilmente stai inserendo un gruppo degli stessi (o simili) valori PersonId contemporaneamente, il che sta causando questo lavoro extra in vari punti della tabella e la frammentazione ti sta uccidendo. Lo svantaggio del passaggio alla PK in cluster nel tuo caso è che se oggi hai problemi di inserimento su PersonIds che variano in valore distribuito in tutta la tabella, se cambi il tuo indice cluster in PK e tutti gli inserimenti ora avvengono in uno posizione, il problema potrebbe effettivamente peggiorare a causa della maggiore concentrazione di contese. (D'altro canto, se i tuoi inserti oggi non sono sparsi ovunque, ma sono tutti tipicamente raggruppati in aree simili, allora il tuo problema probabilmente si risolverà spostando il tuo indice cluster da PersonId al tuo PK perché ridurrai al minimo il frammentazione.)

I tuoi problemi di prestazioni dovrebbero essere analizzati in base alla tua situazione unica e prendere questi tipi di risposte solo come linee guida generali. La soluzione migliore è affidarsi a un DBA in grado di convalidare esattamente dove si trovano i tuoi problemi. Sembra che tu abbia problemi di contesa di risorse che potrebbero andare oltre una semplice modifica dell'indice. Questo potrebbe essere un sintomo di un problema molto più grande. (Probabili problemi di progettazione ... altrimenti limitazioni delle risorse.)

In ogni caso, buona fortuna!


5

Alcuni autori suggeriscono di non "sprecare" il CIsu una identitycolonna se esiste un'alternativa a vantaggio delle query di intervallo.

Da MSDN Clustered Index Design Guidelines, la chiave deve essere scelta in base ai seguenti criteri

  1. Può essere utilizzato per query utilizzate di frequente.
  2. Fornire un alto grado di unicità.
  3. Può essere utilizzato nelle query di intervallo.

La tua CourtOrderIDcolonna si incontra 2. I tuoi PersonIdincontri 1e 3. Poiché la maggior parte delle righe finirà uniqueifiercomunque con l' aggiunta, potresti anche dichiararla come unica e utilizzarla PersonId,CourtOrderIDpoiché avrà la stessa larghezza ma sarà più utile poiché la chiave dell'indice cluster viene aggiunta a tutti gli NCI come localizzatore di righe e questo consentirà per coprire più domande.

Il problema principale dell'utilizzo PersonId,CourtOrderIDcome elemento della configurazione è che probabilmente ne deriverà la frammentazione logica (e questo influisce in particolare sulle query di intervallo che si sta tentando di aiutare), quindi è necessario monitorare il fattore di riempimento ei livelli di frammentazione ed eseguire la manutenzione dell'indice più spesso.


3

È spiegato nel seguente collegamento: https://msdn.microsoft.com/en-us/ms190457.aspx

Raggruppato

  • Gli indici raggruppati ordinano e archiviano le righe di dati nella tabella o nella vista in base ai valori chiave. Queste sono le colonne incluse nella definizione dell'indice. Può esserci un solo indice cluster per tabella, poiché le righe di dati possono essere ordinate in un solo ordine.

  • L'unica volta che le righe di dati in una tabella vengono archiviate in ordine ordinato è quando la tabella contiene un indice cluster. Quando una tabella ha un indice cluster, la tabella viene chiamata tabella cluster. Se una tabella non ha un indice cluster, le sue righe di dati vengono archiviate in una struttura non ordinata chiamata heap.

Non cluster

  • Gli indici non cluster hanno una struttura separata dalle righe di dati. Un indice non cluster contiene i valori della chiave dell'indice non cluster e ogni voce del valore della chiave ha un puntatore alla riga di dati che contiene il valore della chiave .

  • Il puntatore da una riga di indice in un indice non cluster a una riga di dati è chiamato localizzatore di riga. La struttura del localizzatore di righe dipende dal fatto che le pagine di dati siano archiviate in un heap o in una tabella cluster. Per un heap, un localizzatore di riga è un puntatore alla riga. Per una tabella cluster, l'indicatore di riga è la chiave dell'indice cluster.

  • È possibile aggiungere colonne non chiave al livello foglia dell'indice non cluster per ignorare i limiti di chiavi dell'indice esistenti, 900 byte e 16 colonne chiave ed eseguire query completamente coperte e indicizzate.


-3

Alcuni db con alcune cattive selezioni, si uniscono a una procedura memorizzata - l'unica differenza è l'indice

INDICI: cluster e non cluster

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
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.