Índices de SQL Server: ascendente o descendente, ¿qué diferencia hay?

138

Cuando crea un índice en una columna o número de columnas en MS SQL Server (estoy usando la versión 2005), puede especificar que el índice en cada columna sea ascendente o descendente. Me cuesta entender por qué esta opción está aquí. Usando técnicas de ordenamiento binario, ¿no sería una búsqueda tan rápida en ambos sentidos? ¿Qué diferencia hace qué orden elijo?

Joshua Carmody
fuente

Respuestas:

136

Esto es principalmente importante cuando se usa con índices compuestos:

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

se puede usar para:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

o:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

, pero no para:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

Un índice en una sola columna se puede usar de manera eficiente para ordenar de ambas maneras.

Vea el artículo en mi blog para más detalles:

Actualizar:

De hecho, esto puede importar incluso para un índice de una sola columna, aunque no es tan obvio.

Imagine un índice en una columna de una tabla agrupada:

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

El índice en col1mantiene valores ordenados col1junto con las referencias a filas.

Como la tabla está agrupada, las referencias a las filas son en realidad los valores de pk. También se ordenan dentro de cada valor de col1.

Esto significa que las hojas del índice están realmente ordenadas (col1, pk)y esta consulta:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

No necesita clasificación.

Si creamos el índice de la siguiente manera:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

, los valores de col1se ordenarán de forma descendente, pero los valores de pkdentro de cada valor de col1se ordenarán de forma ascendente.

Esto significa que la siguiente consulta:

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

puede ser servido por ix_mytable_col1_descpero no por ix_mytable_col1.

En otras palabras, las columnas que constituyen un CLUSTERED INDEXen cualquier tabla son siempre las columnas finales de cualquier otro índice en esa tabla.

Quassnoi
fuente
1
Cuando dices "no para ..." ¿quieres decir que no funcionará o el rendimiento será horrible?
Neil N
55
Quiero decir que el índice no se usará para la consulta. La consulta en sí funcionará, por supuesto, pero el rendimiento será pobre.
Quassnoi
1
En la primera sección, ¿no debería el segundo ejemplo decir "ORDER BY col1 DESC, col2 DESC"?
Mitch Wheat
71

Para un verdadero índice de una sola columna, hace poca diferencia desde el punto de vista del Optimizador de consultas.

Para la definición de la tabla

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

La consulta

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

Utiliza un escaneo ordenado con dirección de escaneo BACKWARDcomo se puede ver en el Plan de ejecución. Sin embargo, existe una ligera diferencia en que actualmente solo los FORWARDescaneos pueden ser paralelos.

Plan

Sin embargo , puede hacer una gran diferencia en términos de fragmentación lógica . Si el índice se crea con claves descendentes pero se agregan nuevas filas con valores de claves ascendentes, entonces puede terminar con cada página fuera de orden lógico. Esto puede afectar gravemente el tamaño de las lecturas de E / S al escanear la tabla y no está en caché.

Ver los resultados de fragmentación

                    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

para el guión a continuación

/*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 

Es posible usar la pestaña de resultados espaciales para verificar la suposición de que esto se debe a que las páginas posteriores tienen valores clave ascendentes en ambos casos.

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 %% )

ingrese la descripción de la imagen aquí

Martin Smith
fuente
Gracias Martin por este gran CONSEJO, esto realmente me ayudó en las consultas de rango
TheGameiswar
Me pregunto si tengo un índice descendente, luego selecciono mycolumn de mytable donde indexed_column = \ @myvalue es más rápido cuando \ @myvalue está más cerca del valor máximo posible que en el caso cuando \ @myvalue está cerrado al mínimo valor posible.
Lajos Arpad
@LajosArpad, ¿por qué uno sería más rápido? Los árboles B son árboles equilibrados. La profundidad del árbol es la misma para ambos.
Martin Smith
@MartinSmith la profundidad es la misma, pero dudo que el orden de los hermanos no haga la diferencia
Lajos Arpad
@MartinSmith, si el orden de los hermanos tiene incluso una ligera diferencia en el rendimiento, entonces se sumarían millones de selecciones, sin mencionar las uniones multidimensionales.
Lajos Arpad
8

El orden de clasificación es importante cuando desea recuperar muchos datos ordenados, no registros individuales.

Tenga en cuenta que (como sugiere con su pregunta) el orden de clasificación suele ser mucho menos significativo que las columnas que está indexando (el sistema puede leer el índice al revés si el orden es opuesto a lo que quiere). Raramente pienso en el orden de clasificación, mientras que me preocupan las columnas cubiertas por el índice.

@Quassnoi proporciona un gran ejemplo de cuando no importa.

Michael Haren
fuente