Diferencia monumental en el tiempo de ejecución entre consultas cuando se utiliza la sugerencia de consulta RECOMPILE

16

Tengo dos consultas casi idénticas ejecutándose en la misma instancia de SQL Server 2005:

  1. La primera es la SELECTconsulta original generada por LINQ (lo sé, lo sé ... No soy el desarrollador de la aplicación, solo el DBA :).
  2. El segundo es exactamente el mismo que el primero, se agregó un OPTION (RECOMPILE)al final.

Nada más ha sido cambiado.

El primero tarda 55 segundos cada vez que se ejecuta.
El segundo toma 2 segundos.

Ambos conjuntos de resultados son idénticos.

¿Por qué esta pista generaría una ganancia tan dramática en el rendimiento?

La entrada de Books Online RECOMPILEno ofrece una explicación muy detallada:

Indica al Motor de base de datos de SQL Server que descarte el plan generado para la consulta después de que se ejecute, lo que obliga al optimizador de consultas a volver a compilar un plan de consulta la próxima vez que se ejecute la misma consulta. Sin especificar RECOMPILE, el Motor de base de datos almacena en caché los planes de consulta y los reutiliza. Al compilar planes de consulta, la sugerencia de consulta RECOMPILE utiliza los valores actuales de cualquier variable local en la consulta y, si la consulta está dentro de un procedimiento almacenado, los valores actuales pasan a cualquier parámetro.

RECOMPILE es una alternativa útil para crear un procedimiento almacenado que utiliza la cláusula WITH RECOMPILE cuando solo se debe volver a compilar un subconjunto de consultas dentro del procedimiento almacenado, en lugar de todo el procedimiento almacenado. Para obtener más información, consulte Volver a compilar procedimientos almacenados. RECOMPILE también es útil cuando crea guías de plan. Para obtener más información, consulte Optimización de consultas en aplicaciones implementadas mediante guías de plan.

Dado que mi consulta tiene muchas variables locales, supongo que SQL Server puede (seriamente) optimizarla cuando uso la OPTION (RECOMPILE)sugerencia de consulta.

Por todas partes que miro, la gente dice que OPTION (RECOMPILE)debería evitarse. La explicación de esto es que, en general, al usar esta sugerencia, SQL Server no puede reutilizar este plan de ejecución y, por lo tanto, tiene que perder el tiempo volviéndolo a compilar cada vez.
(Pero) Dada la gigantesca ventaja de rendimiento, me inclino a pensar que usar esta sugerencia de consulta esta vez sería algo bueno.

¿Debo usarlo? Si no, ¿hay alguna manera de forzar a SQL Server a usar un mejor plan de ejecución sin esta sugerencia y sin alterar la aplicación?

ivanmp
fuente

Respuestas:

16

Como se documenta en el artículo Estadísticas utilizadas por el Optimizador de consultas en Microsoft SQL Server 2005

Si utiliza una variable local en un predicado de consulta en lugar de un parámetro o literal, el optimizador recurre a una estimación de calidad reducida o una suposición para la selectividad del predicado. Use parámetros o literales en la consulta en lugar de variables locales

Cuando el optimizador no tiene estadísticas utilizables para una columna, adivinará que un =predicado coincidirá con el 10% de las filas, el BETWEEN9%, y cualquiera de >, >=, < and <=ellos coincidirá con el 30%. Si hay estadísticas de columna disponibles, un =predicado se tratará de manera diferente como se muestra a continuación.

Incluso cuando se usan variables locales en una consulta, se usa una estimación mejor que una suposición en el caso de predicados de igualdad. La selectividad para las condiciones de la forma " @local_variable = column_name" se estima utilizando la frecuencia de valor promedio del histograma para column_name. Entonces, por ejemplo, si la columna nombre_columna contiene todos los valores únicos, 1/(number of unique values in column)se utilizará una estimación de selectividad de , que es precisa.

Entonces, esto es esencialmente lo mismo que usar para OPTIMIZE FOR (UNKNOWN). Es muy posible que sea más preciso que una 10%suposición simple, pero no se adapta a los valores específicos que está consultando.

Para obligar a SQL Server a optimizar una consulta cada vez que se ejecuta, y usar los valores de variables locales para estimar la cardinalidad y el costo durante la optimización de la consulta, agregue la RECOMPILEsugerencia de consulta a la consulta.

Con el uso de RECOMPILEusted, presumiblemente, obtendrá estimaciones de cardinalidad más precisas y, por lo tanto, un plan diferente con órdenes de unión / tipos de unión más adecuados para el número de filas devueltas desde diferentes partes de su consulta real.

Martin Smith
fuente