Perché l'ottimizzatore dovrebbe scegliere Indice cluster + Ordina invece di Indice non cluster?


11

Dato il prossimo esempio:

IF OBJECT_ID('dbo.my_table') IS NOT NULL
    DROP TABLE [dbo].[my_table];
GO

CREATE TABLE [dbo].[my_table]
(
    [id]    int IDENTITY (1,1)  NOT NULL PRIMARY KEY,
    [foo]   int                 NULL,
    [bar]   int                 NULL,
    [nki]   int                 NOT NULL
);
GO

/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
    ABS(CHECKSUM(NewId())) % 14,
    ABS(CHECKSUM(NewId())) % 20,
    n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM 
    sys.all_objects AS s1 
CROSS JOIN 
    sys.all_objects AS s2
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC);
GO

Se recupero tutti i record ordinati per [nki](indice non cluster):

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms

L'ottimizzatore sceglie l'indice cluster e quindi applica un algoritmo di ordinamento.

inserisci qui la descrizione dell'immagine

Execution plan

Ma se lo costringo a utilizzare l'indice non cluster:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms

Quindi utilizza un indice non cluster con una ricerca chiave:

inserisci qui la descrizione dell'immagine

Execution plan

Ovviamente se l'indice non cluster viene trasformato in un indice di copertura:

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC)
    INCLUDE (id, foo, bar);
GO

Quindi utilizza solo questo indice:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms

inserisci qui la descrizione dell'immagine

Execution plan


Domanda

  • Perché SQL Server utilizza l'indice cluster più un algoritmo di ordinamento anziché utilizzare un indice non cluster anche se in quest'ultimo caso il tempo di esecuzione è più veloce del 38%?

1
Intendevi lasciare ORDER BY nella tua query a indice forzato?
Forrest,

Risposte:


9

Perché SQL Server utilizza l'indice cluster più un algoritmo di ordinamento anziché utilizzare un indice non cluster anche se in quest'ultimo caso il tempo di esecuzione è più veloce del 38%?

Perché SQL Server utilizza un ottimizzatore basato sui costi basato su statistiche, non su informazioni di runtime.

Durante il processo di stima dei costi per questa query, in realtà valuta il piano di ricerca, ma stima richiederà uno sforzo maggiore. (Notare il "Costo sottotree stimato" quando si passa con il mouse sopra SELEZIONA nel piano di esecuzione). Anche questo non è necessariamente un cattivo presupposto: sulla mia macchina di prova, il piano di ricerca richiede 6 volte la CPU dell'ordinamento / scansione.

Cerca la risposta di Rob Farley sul perché SQL Server potrebbe costare di più il piano di ricerca.


9

Se dovessi confrontare il numero di letture richieste in 100.000 ricerche con ciò che è coinvolto in un ordinamento, potresti avere rapidamente un'idea del perché lo Strumento per ottimizzare le query calcola che CIX + Sort sarebbe la scelta migliore.

L'esecuzione della ricerca finisce per essere più veloce perché le pagine da leggere sono in memoria (anche se si cancella la cache, si hanno molte righe per pagina, quindi si leggono le stesse pagine più volte, ma con diverse quantità di frammentazione o pressione della memoria diversa da altre attività, questo potrebbe non essere il caso). In realtà non ci vorrebbe molto per avere CIX + Sort più veloce, ma quello che stai vedendo è perché il costo di una lettura non tiene conto del costo relativamente basso di colpire ripetutamente le stesse pagine.


4

Ho deciso di scavare un po 'su questa domanda e ho scoperto alcuni documenti interessanti che parlavano di come e quando usare o forse meglio, non (forzare) l'uso di un indice non cluster.

Come suggerito dai commenti di John Eisbrener , uno dei più citati, anche in altri blog, è questo interessante articolo di Kimberly L. Tripp:

ma non è l'unico, se sei interessato puoi dare un'occhiata a queste pagine:

Come puoi vedere, tutti si muovono attorno al concetto di punto di ribaltamento .

Citato dall'articolo di KL Tripp

Qual è il punto critico?

È il punto in cui il numero di righe restituite non è " abbastanza selettivo ". SQL Server sceglie di NON utilizzare l'indice non cluster per cercare le righe di dati corrispondenti e invece esegue una scansione della tabella.

Quando SQL Server utilizza un indice non cluster su un heap, in pratica ottiene un elenco di puntatori alle pagine della tabella di base. Quindi utilizza questi puntatori per recuperare le righe con una serie di operazioni denominate Ricerche ID riga (RID). Ciò significa che almeno utilizzerà tutte le letture di pagina quante sono state restituite le righe e forse altre. Il processo è in qualche modo simile con un indice cluster come tabella di base, con lo stesso risultato: più letture.

Ma quando si verifica quel punto critico?

Naturalmente come la maggior parte delle cose in questa vita, dipende ...

No sul serio, si verifica tra il 25% e il 33% del numero di pagine nella tabella, a seconda di quante righe per pagina. Ma ci sono altri fattori che dovresti considerare:

Citato dall'articolo di ITPRoToday

Altri fattori che influenzano il punto di ribaltamento Sebbene il costo delle ricerche RID sia il fattore più importante che influenza il punto di ribaltamento, ci sono una serie di altri fattori:

  • L'I / O fisico è molto più efficiente durante la scansione di un indice cluster. I dati dell'indice cluster vengono posizionati in sequenza sul disco in ordine di indice. Di conseguenza, sul disco è presente una corsa della testa laterale molto ridotta, che migliora le prestazioni di I / O.
  • Quando il motore di database esegue la scansione di un indice cluster, sa che esiste un'alta probabilità che le prossime pagine sulla traccia del disco contengano ancora i dati di cui ha bisogno. Quindi, inizia a leggere in anticipo in blocchi da 64 KB anziché nelle normali pagine da 8 KB. Ciò comporta anche un I / O più veloce.

Ora, se eseguo di nuovo le mie query utilizzando le statistiche IO:

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WHERE nki < 20000 ORDER BY nki ;
SET STATISTICS IO OFF;

Logical reads: 312

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS IO OFF;

Logical reads: 41293

La seconda query richiede più letture logiche rispetto alla prima.

Devo evitare l'indice non cluster?

No, un indice cluster può essere utile, ma vale la pena impiegare del tempo e fare uno sforzo in più per analizzare ciò che stai cercando di ottenere con esso.

Citato dall'articolo di KL Tripp

Quindi cosa dovresti fare? Dipende. Se conosci bene i tuoi dati e fai alcuni test approfonditi che potresti prendere in considerazione usando un suggerimento (ci sono alcune cose intelligenti che puoi fare programmaticamente in sps, proverò a dedicare un post a questo presto). Tuttavia, una scelta molto migliore (se possibile) è quella di considerare la copertura (questo è davvero il mio punto principale :). Nelle mie query, la copertura non è realistica perché le mie query vogliono tutte le colonne (il male SELEZIONA *) ma, se le tue query sono più strette E hanno priorità alta, stai meglio con un indice di copertura (in molti casi) su un suggerimento perché un indice che copre una query, mai suggerimenti.

Questa è la risposta al puzzle per ora, ma c'è sicuramente molto altro in cui tuffarsi. Il Tipping Point può essere un'ottima cosa - e di solito funziona bene. Ma, se stai scoprendo che puoi forzare un indice e ottenere prestazioni migliori, potresti voler investigare e vedere se è questo. Quindi considera la probabilità che un suggerimento sia di aiuto e ora sai dove concentrarti.

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.