Index SEEK no se usa a menos que OPTION (RECOMPILE)?

11

(Pregunta movida de SO)

Tengo una tabla (datos ficticios) con índice agrupado que contiene 2 columnas:

ingrese la descripción de la imagen aquí

Ahora ejecuto esas dos consultas:

declare 
@productid int =1 , 
@priceid  int = 1




SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid OR @productid IS NULL)
       AND (priceid = @priceid OR @priceid IS NULL)  


SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid)
       AND (priceid = @priceid)

El plan de ejecución real para ambas consultas es:

ingrese la descripción de la imagen aquí

Como puede ver, el primero usa SCAN mientras que el segundo usa SEEK.

Sin embargo, agregando OPTION (RECOMPILE)a la primera consulta, hizo el plan de ejecución también para usar SEEK:

ingrese la descripción de la imagen aquí

Amigos en el chat de DBA me dijeron que:

En su consulta, @ productid = 1, lo que significa que (productID = @ productID OR @productID IS NULL) puede simplificarse a (productID = @ productID). El primero requiere un escaneo para funcionar con cualquier valor de @productID, el último podría usar una búsqueda. Entonces, cuando usa RECOMPILE, SQL Server analizará qué valor tiene realmente en @productID y hará el mejor plan para ello. Con un valor no nulo en @productID, una búsqueda es lo mejor. Si se desconoce el valor de @productID, el plan debe adaptarse a cualquier valor posible en @productID, lo que requeriría un escaneo. Tenga cuidado: OPTION (RECOMPILE) forzará una recompilación del plan cada vez que lo ejecute, lo que agregará unos pocos milisegundos a cada ejecución. Aunque esto solo es un problema si la consulta se ejecuta con mucha frecuencia.

También :

Si @productID es nulo, ¿qué valor buscarías? Respuesta: no hay nada que buscar. Todos los valores califican.

Entiendo que OPTION (RECOMPILE)obliga a SQL Server a ver qué valores reales tienen los parámetros y ver si puede BUSCAR con ellos.

Pero ahora pierdo el beneficio de la compilación anticipada.

Pregunta

En mi humilde opinión, SCAN solo ocurrirá si un parámetro es nulo.
Está bien: deje que SQL SERVER cree un plan de ejecución para SCAN.
PERO si SQL Server ve que ejecuto esta consulta muchas veces con valores: 1,1entonces, ¿por qué no crea OTRO plan de ejecución y usa SEEK para eso?

AFAIK - SQL crea un plan de ejecución para las consultas más exitosas .

  • ¿Por qué SQL SERVER no guarda un plan de ejecución para:

    @productid int =1 , @priceid int = 1

(Lo ejecuto muchas veces con esos valores)

  • ¿Es posible forzar a SQL a mantener ese plan de ejecución (que usa SEEK) para futuras invocaciones?

Crear guión de tabla completo + datos

Royi Namir
fuente
2
Continuemos esta discusión en el chat .
ypercubeᵀᴹ

Respuestas:

10

Resumiendo algunos de los puntos principales de nuestra discusión en la sala de chat :


En términos generales, SQL Server almacena en caché un único plan para cada declaración . Ese plan debe ser válido para todos los posibles valores de parámetros futuros .

No es posible almacenar en caché un buscan plan para su consulta, ya que el plan no sería válida si, por ejemplo, @productid es nulo.

En algunas versiones futuras, SQL Server podría admitir un plan único que elija dinámicamente entre un escaneo y una búsqueda, dependiendo de los valores de los parámetros de tiempo de ejecución, pero eso no es algo que tengamos hoy.

Clase de problema general

Su consulta es un ejemplo de un patrón referido de varias maneras como una consulta de "capturar todo" o "búsqueda dinámica". Existen varias soluciones, cada una con sus propias ventajas y desventajas. En las versiones modernas de SQL Server (2008+), las opciones principales son:

  • IF bloques
  • OPTION (RECOMPILE)
  • SQL dinámico usando sp_executesql

El trabajo más completo sobre el tema probablemente sea de Erland Sommarskog, que se incluye en las referencias al final de esta respuesta. No hay forma de escapar de las complejidades involucradas, por lo que es necesario invertir algo de tiempo en probar cada opción para comprender las compensaciones en cada caso.

IF bloques

Para ilustrar una IFsolución de bloque para el caso específico en la pregunta:

IF @productid IS NOT NULL AND @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid
        AND T.priceID = @priceid;
END;
ELSE IF @productid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid;
END;
ELSE IF @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.priceID = @priceid;
END;
ELSE
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T;
END;

Contiene una declaración separada para los cuatro posibles casos nulos o no nulos para cada uno de los dos parámetros (o variables locales), por lo que hay cuatro planes.

Existe un problema potencial con el rastreo de parámetros, que podría requerir una OPTIMIZE FORpista en cada consulta. Consulte la sección de referencias para explorar este tipo de sutilezas.

Recompilar

Como se señaló anteriormente y en la pregunta, también puede agregar una OPTION (RECOMPILE)pista para obtener un nuevo plan (buscar o escanear) en cada invocación. Dada la frecuencia relativamente lenta de las llamadas en su caso (una vez cada diez segundos en promedio, con un tiempo de compilación de menos de un milisegundo) parece probable que esta opción sea adecuada para usted:

SELECT
    T.productID,
    T.priceID
FROM dbo.Transactions AS T
WHERE
    (T.productID = @productid OR @productid IS NULL)
    AND (T.priceID = @priceid OR @priceid IS NULL)
OPTION (RECOMPILE);

También es posible combinar características de las opciones anteriores de manera creativa, para aprovechar al máximo las ventajas de cada método, mientras se minimizan las desventajas. Realmente no hay un atajo para comprender estas cosas en detalle, luego hacer una elección informada respaldada por pruebas realistas.

Otras lecturas

Paul White 9
fuente