Differenza di prestazione tra indice cluster e indice non cluster


22

Stavo leggendo Clusterede Non Clustered Indexes.

Clustered Index- Contiene pagine di dati. Ciò significa che le informazioni complete sulla riga saranno presenti nella colonna dell'indice cluster.

Non Clustered Index- Contiene solo le informazioni sul Localizzatore di righe sotto forma di colonna Indice cluster (se disponibile) o Identificatore file + Numero pagina + Righe totali in una pagina. Ciò significa che il motore di query deve compiere un ulteriore passo per individuare i dati effettivi.

Domanda - Come posso controllare la differenza di prestazioni con l'aiuto di un esempio pratico, come sappiamo che la tabella può avere un solo Clustered Indexe fornisce sortingal Clustered Index Columne Non Clustered Indexnon forniscono sortinge può supportare 999 Non Clustered Indexesa SQL Server 2008e 249 a SQL Server 2005.


2
La differenza di prestazione quando fai cosa ?, che tipo di lavoro vuoi fare con quella tabella ?, non esiste un'unica soluzione adatta ad ogni esigenza
Lamak,

2
Qualche discussione concreta qui forse. stackoverflow.com/questions/91688/… stackoverflow.com/questions/5070529/… stackoverflow.com/questions/1251636/… Potremmo scrivere una tesi sulle differenze tra indici cluster e non cluster, ma non credo che direbbe tutto ciò che non è già disponibile per la lettura.
Aaron Bertrand

4
Hai scritto: "Ciò significa che il motore di query deve compiere un ulteriore passaggio per individuare i dati effettivi". In realtà, se tutto ciò che serve sono le colonne coperte dall'indice , non è necessario eseguire ulteriori passaggi dopo aver trovato le righe di destinazione nell'indice non cluster. Solo quando sono necessarie colonne non coperte dall'indice non cluster, SQL Server deve eseguire una ricerca nei segnalibri .
Nick Chammas,

Risposte:


43

Ottima domanda in quanto è un concetto così importante. Questo è un argomento importante e ciò che sto per mostrarti è una semplificazione in modo da poter comprendere i concetti di base.

In primo luogo quando vedi la tabella di pensiero indice cluster . Nel server SQL se una tabella non contiene un indice cluster è un heap. La creazione di un indice cluster sulla tabella trasforma effettivamente la tabella in una struttura di tipo b-tree. L'indice cluster È la tua tabella, non è separato dalla tabella

Ti sei mai chiesto perché puoi avere un solo indice cluster? Bene, se avessimo due indici raggruppati avremmo bisogno di due copie della tabella. Dopotutto contiene i dati.

Proverò a spiegarlo usando un semplice esempio.

NOTA: ho creato la tabella in questo esempio e l'ho riempita con oltre 3 milioni di voci casuali. Quindi ha eseguito le query effettive e incollato qui i piani di esecuzione.

Ciò di cui hai veramente bisogno è la notazione O o l' efficienza operativa . Supponiamo che tu abbia la seguente tabella.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Quindi qui abbiamo una tabella di base con una chiave cluster su CustomerID (la chiave primaria è raggruppata per impostazione predefinita). Pertanto, la tabella viene organizzata / ordinata in base alla chiave primaria CustomerID. I livelli intermedi conterranno i valori CustomerID. Le pagine di dati conterranno l'intera riga, quindi è la riga della tabella.

Creeremo anche un indice non cluster nel campo CustomerName. Il seguente codice lo farà.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Quindi in questo indice troverai nelle pagine di dati / nodi a livello foglia un puntatore ai livelli intermedi nell'indice cluster. L'indice è organizzato / ordinato attorno al campo CustomerName. Pertanto, il livello intermedio contiene i valori CustomerName e il livello foglia conterrà il puntatore (questi valori del puntatore sono in realtà i valori della chiave primaria o la colonna CustomerID).

Bene, quindi se eseguiamo la seguente query:

SELECT * FROM Customer WHERE CustomerID = 1 

Probabilmente SQL leggerà l'indice cluster tramite un'operazione di ricerca. Un'operazione di ricerca è una ricerca binaria che è molto più efficiente di una scansione che è una ricerca sequenziale. Quindi nel nostro esempio sopra l'indice viene letto e usando una ricerca binaria SQL può eliminare i dati che non corrispondono ai criteri che stiamo cercando. Vedi la schermata allegata per il piano di query.

inserisci qui la descrizione dell'immagine

Quindi il numero di operazioni o Notazione O per l'operazione di ricerca è il seguente:

  1. Effettua la ricerca binaria sull'indice cluster confrontando il valore cercato con i valori a livello intermedio.
  2. Restituisce i valori corrispondenti (ricorda che l'indice cluster ha tutti i dati in esso contenuti può restituire tutte le colonne dall'indice in quanto sono i dati della riga)

Quindi sono due operazioni. Tuttavia, se abbiamo eseguito la seguente query:

SELECT * FROM Customer WHERE CustomerName ='John'

SQL ora utilizzerà l'indice non cluster sul CustomerName per eseguire la ricerca. Tuttavia, poiché si tratta di un indice non cluster, non contiene tutti i dati nella riga.

Quindi SQL eseguirà la ricerca a livelli intermedi per trovare i record corrispondenti quindi eseguirà una ricerca utilizzando i valori restituiti per eseguire un'altra ricerca sull'indice cluster (ovvero la tabella) per recuperare i dati effettivi. Sembra confuso, lo so, ma continuate a leggere e tutto diventerà chiaro.

Poiché il nostro indice non cluster contiene solo il campo CustomerName (i valori dei campi indicizzati archiviati nei nodi intermedi) e il puntatore ai dati che è CustomerID, l'indice non ha alcuna registrazione del CustomerSurname. Il Cognome cliente deve essere recuperato dall'indice o dalla tabella cluster.

Quando eseguo questa query ottengo il seguente piano di esecuzione:

inserisci qui la descrizione dell'immagine

Ci sono due cose importanti da notare nella schermata qui sopra

  1. SQL sta dicendo che ho un indice mancante (il testo in verde). SQL sta suggerendo di creare un indice su CustomerName che includa CustomerID e CustomerSurname.
  2. Vedrai anche che il 99% del tempo della query viene impiegato per eseguire una ricerca della chiave sull'indice della chiave primaria / indice cluster.

Perché SQL suggerisce di nuovo l'indice su CustomerName? Bene, poiché l'indice contiene solo CustomerID e CustomerName SQL deve ancora trovare CustomerSurname dalla tabella / dagli indici cluster.

Se abbiamo creato l'indice e includessimo la colonna CustomerSurname nell'indice, SQL sarebbe in grado di soddisfare l'intera query semplicemente leggendo l'indice non cluster. Questo è il motivo per cui SQL sta suggerendo di cambiare il mio indice non cluster.

Qui puoi vedere l'operazione aggiuntiva che SQL deve fare per ottenere la colonna CustomerSurname dalla chiave cluster

Pertanto, il numero di operazioni è il seguente:

  1. Effettua la ricerca binaria su un indice non cluster confrontando il valore cercato con i valori nel livello intermedio
  2. Per i nodi corrispondenti leggere il nodo a livello di foglia che conterrà il puntatore per i dati nell'indice cluster (i nodi a livello di foglia conterranno comunque i valori della chiave primaria).
  3. Per ogni valore restituito, fai una lettura sull'indice cluster (la tabella) per ottenere i valori di riga qui, leggeremo il Cognome del cliente.
  4. Restituisce le righe corrispondenti

Sono 4 operazioni per ottenere i valori. Il doppio della quantità di operazioni necessarie rispetto alla lettura dell'indice cluster. Lo dimostra che il tuo indice cluster è il tuo indice più potente in quanto contiene tutti i dati.

Quindi, solo per chiarire un ultimo punto. Perché dico che il puntatore nell'indice non cluster è il valore della chiave primaria? Bene per dimostrare che i nodi a livello foglia dell'indice non cluster contengono il valore della chiave primaria, cambio la mia query in:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

In questa query SQL può leggere l'ID cliente dall'indice non cluster. Non è necessario effettuare una ricerca sull'indice cluster. Questo si può vedere dal piano di esecuzione che assomiglia a questo.

inserisci qui la descrizione dell'immagine

Notare la differenza tra questa query e la query precedente. Non c'è ricerca. SQL può trovare tutti i dati nell'indice non cluster

Spero che tu possa iniziare a capire che l'indice cluster è la tabella e che gli indici non cluster NON contengono tutti i dati. L'indicizzazione accelera le selezioni a causa del fatto che è possibile eseguire ricerche binarie ma solo gli indici cluster contengono tutti i dati. Pertanto, una ricerca su un indice non cluster determinerà quasi sempre il caricamento di valori dall'indice cluster. Queste operazioni extra rendono gli indici non cluster meno efficienti di un indice cluster.

Mi auguro questo chiarisca tutto. Se qualcosa non ha senso, si prega di inviare un commento e cercherò di chiarire. È piuttosto tardi qui e il mio cervello si sente un po 'piatto. Tempo per un toro rosso.


Ho una domanda. Perché è la ricerca che un indice cerca nell'indice non cluster su CustomerName per questa query SELEZIONA * DA Customer DOVE CustomerName = 'John'. Poiché si tratta di un indice non cluster, il nome utente personalizzato non verrà ordinato. Quindi non dovrebbe essere eseguita una scansione dell'indice.
ckv,

BTW Ottima risposta totalmente compresa tranne la domanda di cui sopra.
ckv,

1
Un indice viene ordinato nell'ordine dei dati. Ad esempio, verrebbe ordinato in base al nome del cliente poiché è il valore indicizzato. Quindi è ordinato. Ricorda che deve ancora eseguire la scansione del livello foglia o delle pagine.
Namphibian,

9

"Ciò significa che il motore di query deve compiere un ulteriore passo per individuare i dati effettivi."

Non necessariamente: se l'indice copre una determinata query, non è necessario effettuare alcun viaggio nelle pagine dei dati. Inoltre, con le colonne incluse, è possibile aggiungere colonne aggiuntive a un indice non cluster per renderlo coperto senza alterare la dimensione della chiave.

Quindi la risposta definitiva è - Dipende (da molte più informazioni di quelle che puoi davvero coprire in una singola domanda) - devi capire tutte le capacità degli indici e il piano di esecuzione di una determinata query potrebbe differire dalle tue aspettative.

Una regola generale che ho è che una tabella ha sempre un indice cluster (e di solito su un'identità o un GUID sequenziale), ma gli indici non cluster vengono aggiunti per le prestazioni. Ma ci sono sempre delle eccezioni: le tabelle heap hanno un posto, gli indici cluster più ampi hanno un posto. Gli indici apparentemente ridondanti che sono più stretti per adattarsi a più righe per pagina hanno un posto. ecc ecc.

E non mi preoccuperei dei limiti sui vari indici consentiti - quasi certamente non entrerà in gioco in molti esempi del mondo reale.


2
+1 per there are always exceptions: troppe persone lo omettono e pensano che ogni indice raggruppato dovrebbe essere una int identityquestione qualunque.
JNK,
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.