sql - que - mongodb español
Índices de SQL Server: ascendente o descendente, ¿qué diferencia hace? (3)
El orden de clasificación importa cuando desea recuperar muchos datos ordenados, no registros individuales.
Tenga en cuenta que (como está sugiriendo con su pregunta) el orden de clasificación suele ser mucho menos significativo que las columnas que indexa (el sistema puede leer el índice en reversa si el orden es opuesto a lo que quiere). Raramente le doy un orden de clasificación de índice a cualquier pensamiento, mientras que agonizo sobre las columnas cubiertas por el índice.
@Quassnoi proporciona un excelente ejemplo de cuándo importa.
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 elección está aquí. Usando técnicas de clasificación binarias, ¿no sería una búsqueda igual de rápida en ambos sentidos? ¿Qué diferencia hace qué orden elijo?
Esto es primordialmente 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 clasificar en ambos sentidos.
Ver el artículo en mi blog para más detalles:
Actualizar:
De hecho, esto puede importar incluso para un índice de columna individual, 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 col1
mantiene los valores ordenados de col1
junto con las referencias a filas.
Como la tabla está agrupada, las referencias a 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 actualmente 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)
, entonces los valores de col1
se ordenarán descendentemente, pero los valores de pk
dentro de cada valor de col1
se 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_desc
pero no por ix_mytable_col1
.
En otras palabras, las columnas que constituyen un CLUSTERED INDEX
en cualquier tabla son siempre las columnas finales de cualquier otro índice en esa tabla.
Para un verdadero índice de una sola columna, hay 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 la dirección de escaneo BACKWARD
como se puede ver en el Plan de ejecución. Sin embargo, existe una ligera diferencia en el hecho de que actualmente solo los escaneos FORWARD
se pueden paralelizar.
Sin embargo , puede marcar una gran diferencia en términos de fragmentación lógica . Si el índice se crea con teclas que descienden, pero las nuevas filas se anexan con valores de clave ascendentes, puede terminar con cada página fuera de orden lógico. Esto puede afectar seriamente el tamaño de las lecturas de E / S al escanear la tabla y no está en la memoria 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 script 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 de 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 %% )