¿Qué factores de coste van al optimizador al elegir diferentes tipos de bobinas?

15

Spoolum

En SQL Server hay varios tipos de carretes. Los dos que me interesan son los carretes de tabla y los carretes de índice , fuera de las consultas de modificación .

Las consultas de solo lectura, particularmente en el lado interno de una unión de Nested Loops, pueden usar una tabla o un carrete de índice para reducir potencialmente las E / S y mejorar el rendimiento de las consultas. Estos carretes pueden ser ansiosos o perezosos . Justo como tu y yo.

Mis preguntas son:

  • Qué factores intervienen en la elección de la tabla frente al carrete de índice
  • Qué factores intervienen en la elección entre Eager y Lazy Spools
Erik Darling
fuente

Respuestas:

12

Esto es un poco amplio, pero creo que entiendo la verdadera pregunta y responderé en consecuencia. Sin embargo, solo voy a hablar sobre el carrete de tabla vs índice. No creo que sea correcto verlo allí como una elección entre carretes de tabla e índice. Como sabe, en un solo subárbol es posible obtener un carrete de índice, un carrete de tabla o tanto un carrete de índice como un carrete de tabla. Creo que generalmente es correcto decir que obtienes un carrete de índice en las siguientes condiciones:

  1. El optimizador de consultas tiene una razón para transformar una unión en una aplicación
  2. El optimizador de consultas realmente realiza la transformación a la aplicación
  3. El optimizador de consultas usa la regla para agregar una cola de índice (como mínimo, la cola de índice debe ser segura de usar)
  4. Se selecciona el plan con el carrete de índice.

Puede ver la mayoría de estos con demostraciones simples. Comience creando un par de montones:

DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;


DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Para la primera consulta, no hay nada que buscar:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);

Por lo tanto, no hay ninguna razón para que el optimizador transforme la unión en una aplicación. Terminas con un carrete de mesa debido a razones de costos. Entonces esta consulta falla la primera prueba.

ingrese la descripción de la imagen aquí

Para la siguiente consulta, es justo esperar que el optimizador tenga una razón para considerar una solicitud:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID 
OPTION (LOOP JOIN, MAXDOP 1);

Pero no está destinado a ser:

ingrese la descripción de la imagen aquí

Esta consulta falla la segunda prueba. Una explicación completa está aquí . Citando la parte más relevante:

El optimizador no considera construir un índice sobre la marcha para permitir una aplicación; más bien la secuencia de eventos suele ser al revés: transformar para aplicar porque existe un buen índice.

Puedo reescribir la consulta para alentar al optimizador a considerar una solicitud:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);

Pero todavía no hay una cola de índice:

ingrese la descripción de la imagen aquí

Esta consulta falla la tercera prueba. En SQL Server 2014 había un límite de longitud de clave de índice de 900 bytes. Esto se extendió en SQL Server 2016 pero solo para índices no agrupados. El índice de una cola es un índice agrupado, por lo que el límite permanece en 900 bytes . En cualquier caso, la regla de spool de índice no se puede aplicar porque podría provocar un error durante la ejecución de la consulta.

Reducir la longitud del tipo de datos a 800 finalmente proporciona un plan con un carrete de índice:

ingrese la descripción de la imagen aquí

El plan de spool de índice, no es sorprendente, tiene un costo significativamente más barato que un plan sin spool: 89.7603 unidades frente a 598.832 unidades. Puede ver la diferencia con la QUERYRULEOFF BuildSpoolsugerencia de consulta no documentada :

ingrese la descripción de la imagen aquí

Esta no es una respuesta completa, pero espero que sea algo de lo que estaba buscando.

Joe Obbish
fuente