Indici di SQL Server: crescente o decrescente, che differenza fa?


138

Quando si crea un indice su una colonna o un numero di colonne in MS SQL Server (sto usando la versione 2005), è possibile specificare che l'indice su ciascuna colonna sia crescente o decrescente. Sto facendo fatica a capire perché questa scelta è anche qui. Utilizzando tecniche di ordinamento binario, una ricerca non sarebbe altrettanto veloce in entrambi i modi? Che differenza fa quale ordine scelgo?


Risposte:


136

Ciò è importante soprattutto se utilizzato con indici compositi:

CREATE INDEX ix_index ON mytable (col1, col2 DESC);

può essere utilizzato per:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

o:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

, ma non per:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

Un indice su una singola colonna può essere utilizzato in modo efficiente per l'ordinamento in entrambi i modi.

Vedi l'articolo nel mio blog per i dettagli:

Aggiornare:

In effetti, questo può importare anche per un indice a colonna singola, sebbene non sia così ovvio.

Immagina un indice su una colonna di una tabella cluster:

CREATE TABLE mytable (
       pk INT NOT NULL PRIMARY KEY,
       col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)

L'indice col1attivo mantiene i valori ordinati col1insieme ai riferimenti alle righe.

Poiché la tabella è raggruppata, i riferimenti alle righe sono in realtà i valori di pk. Sono inoltre ordinati entro ciascun valore di col1.

Ciò significa che le foglie dell'indice sono effettivamente ordinate (col1, pk)e questa query:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

non ha bisogno di smistamento.

Se creiamo l'indice come segue:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

, i valori di col1verranno ordinati in ordine decrescente, ma i valori di pkall'interno di ciascun valore di col1verranno ordinati in ordine crescente.

Ciò significa che la seguente query:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk DESC

può essere servito da ix_mytable_col1_descma non da ix_mytable_col1.

In altre parole, le colonne che costituiscono un CLUSTERED INDEXsu qualsiasi tabella sono sempre le colonne finali di qualsiasi altro indice su quella tabella.


1
Quando dici "non per ..." vuoi dire che non funzionerà o che la performance sarà orribile?
— Neil N,

5
Voglio dire che l'indice non verrà utilizzato per la query. La query stessa funzionerà, ovviamente, ma le prestazioni saranno scarse.
— Quassnoi,

1
Nella prima sezione, il secondo esempio non dovrebbe dire "ORDER BY col1 DESC, col2 DESC"?
— Mitch Wheat,

71

Per un vero indice a colonna singola fa poca differenza dal punto di vista di Query Optimizer.

Per la definizione della tabella

CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] ASC))

The Query

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

Utilizza una scansione ordinata con direzione di scansione, BACKWARDcome si può vedere nel Piano di esecuzione. Vi è tuttavia una leggera differenza in quanto attualmente è FORWARDpossibile parallelizzare solo le scansioni.

Piano

Tuttavia , può fare una grande differenza in termini di frammentazione logica . Se l'indice viene creato con chiavi discendenti ma vengono aggiunte nuove righe con valori di chiave ascendenti, è possibile finire con ogni pagina fuori dall'ordine logico. Ciò può influire notevolmente sulla dimensione delle letture IO durante la scansione della tabella e non si trova nella cache.

Vedi i risultati della frammentazione

                    avg_fragmentation                    avg_fragment
name   page_count   _in_percent         fragment_count   _size_in_pages
------ ------------ ------------------- ---------------- ---------------
T1     1000         0.4                 5                200
T2     1000         99.9                1000             1

per lo script qui sotto

/*Uses T1 definition from above*/
SET NOCOUNT ON;

CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] DESC))

BEGIN TRAN

GO
INSERT INTO T1 DEFAULT VALUES
GO 1000
INSERT INTO T2 DEFAULT VALUES
GO 1000

COMMIT

SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 
UNION ALL 
SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 

È possibile utilizzare la scheda dei risultati spaziali per verificare la supposizione che ciò sia dovuto al fatto che le pagine successive presentano valori chiave ascendenti in entrambi i casi.

SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T1
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
UNION ALL
SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T2
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )

inserisci qui la descrizione dell'immagine


Grazie Martin per questo fantastico SUGGERIMENTO, questo mi ha davvero aiutato nelle domande sui ranghi
— TheGameiswar,

Mi chiedo se ho un indice discendente, quindi seleziona mycolumn da mytable dove indexed_column = \ @myvalue è più veloce quando \ @myvalue è più vicino al valore massimo possibile rispetto al caso in cui \ @myvalue è chiuso al valore minimo possibile.
— Lajos Arpad,

@LajosArpad perché uno dovrebbe essere più veloce? Gli alberi B sono alberi equilibrati. La profondità dell'albero è la stessa per entrambi.
— Martin Smith,

@MartinSmith la profondità è la stessa, ma dubito che l'ordine dei fratelli non farebbe differenza
— Lajos Arpad

@MartinSmith, se l'ordine dei fratelli ha anche una leggera differenza nelle prestazioni, si sommerebbero milioni di selezioni, per non parlare dei join multidimensionali.
— Lajos Arpad,

8

Il criterio di ordinamento è importante quando si desidera recuperare molti dati ordinati, non singoli record.

Nota che (come suggerisci con la tua domanda) l'ordinamento è in genere molto meno significativo di quello delle colonne che stai indicizzando (il sistema può leggere l'indice al contrario se l'ordine è opposto a quello che vuole). Raramente do un po 'di ordine all'indice, mentre mi agonizzo per le colonne coperte dall'indice.

@Quassnoi fornisce un grande esempio di quando si fa importa.

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.