LA OPCIÓN (RECOMPILAR) es Siempre Más Rápida; ¿Por Qué?


Me encontré con una situación extraña en la que agregar OPTION (RECOMPILE) a mi consulta hace que se ejecute en medio segundo, mientras que omitirla hace que la consulta tome más de cinco minutos.

Este es el caso cuando la consulta se ejecuta desde Query Analyzer o desde mi programa C# a través de SqlCommand.ExecuteReader(). Llamar (o no llamar) DBCC FREEPROCCACHE o DBCC dropcleanbuffers no hace ninguna diferencia; los resultados de la consulta siempre se devuelven instantáneamente con OPTION (RECOMPILE) y más de cinco minutos sin él. La consulta siempre se llama con la misma parámetros [para esta prueba].

Estoy usando SQL Server 2008.

Me siento bastante cómodo con escribir SQL, pero nunca he usado un comando OPTION en una consulta antes y no estaba familiarizado con todo el concepto de cachés de plan hasta escanear los mensajes en este foro. Mi comprensión de los mensajes es que OPTION (RECOMPILE) es una operación costosa. Aparentemente crea una nueva estrategia de búsqueda para la consulta. Entonces, ¿por qué es que las consultas posteriores que omiten el OPTION (RECOMPILE) son tan lentas? ¿No deberían las consultas posteriores hacer uso de la estrategia de búsqueda que se calculó en la llamada anterior que incluía la sugerencia de recompilación?

¿Es muy inusual tener una consulta que requiere una sugerencia de recompilación en cada llamada?

Lo siento por la pregunta de nivel de entrada, pero realmente no puedo hacer cara o cruz de esto.

ACTUALIZACIÓN: Se me ha pedido que publique la consulta...

select acctNo,min(date) earliestDate 
from( 
    select acctNo,tradeDate as date 
    from datafeed_trans 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_money 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_jnl 
    where feedid=@feedID and feedDate=@feedDate 
)t1 
group by t1.acctNo
OPTION(RECOMPILE)

Al ejecutar la prueba desde Query Analyzer, antepongo la siguientes líneas:

declare @feedID int
select @feedID=20

declare @feedDate datetime
select @feedDate='1/2/2009'

Cuando lo llamo desde mi programa C#, los parámetros se pasan a través de la propiedad SqlCommand.Parameters.

Para los propósitos de esta discusión, puede asumir que los parámetros nunca cambian, por lo que podemos descartar que el parámetro subóptimo huela como la causa.

Author: Abe Miessler, 2014-01-01

4 answers

Hay veces que usar OPTION(RECOMPILE) tiene sentido. En mi experiencia, la única vez que esta es una opción viable es cuando se está utilizando SQL dinámico. Antes de explorar si esto tiene sentido en su situación, le recomendaría reconstruir sus estadísticas. Esto se puede hacer ejecutando lo siguiente:

EXEC sp_updatestats

Y luego recrear su plan de ejecución. Esto asegurará que cuando se cree su plan de ejecución se utilizará la información más reciente.

Añadiendo OPTION(RECOMPILE) reconstruye la plan de ejecución cada vez que se ejecuta su consulta. Nunca he escuchado que se describe como creates a new lookup strategy pero tal vez solo estamos usando términos diferentes para la misma cosa.

Cuando se crea un procedimiento almacenado (sospecho que está llamando ad-hoc sql desde. NET, pero si está utilizando una consulta parametrizada, entonces esto termina siendo una llamada proc almacenada) SQL Server intenta determinar el plan de ejecución más efectivo para esta consulta en función de los datos en su base de datos y los parámetros (parámetro sniffing), y luego almacena en caché este plan. Esto significa que si crea la consulta donde hay 10 registros en su base de datos y luego la ejecuta cuando hay 100,000,000 registros, el plan de ejecución en caché puede ya no ser el más efectivo.

En resumen - No veo ninguna razón para que OPTION(RECOMPILE) sea un beneficio aquí. Sospecho que sólo necesita actualizar sus estadísticas y su plan de ejecución. La reconstrucción de estadísticas puede ser una parte esencial del trabajo de DBA dependiendo de tu situación. Si sigues teniendo problemas después de actualizar tus estadísticas, te sugiero que publiques ambos planes de ejecución.

Y para responder a su pregunta - sí, diría que es muy inusual que su mejor opción sea recompilar el plan de ejecución cada vez que ejecuta la consulta.

 125
Author: Abe Miessler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 12:42:40

A menudo, cuando hay una diferencia drástica de ejecución a ejecución de una consulta, encuentro que a menudo es uno de los 5 problemas.

  1. ESTADÍSTICAS - Las estadísticas están desactualizadas. Una base de datos almacena estadísticas sobre el rango y la distribución de los tipos de valores en varias columnas en tablas e índices. Esto ayuda al motor de consultas a desarrollar un "Plan" de ataque sobre cómo realizará la consulta, por ejemplo, el tipo de método que utilizará para hacer coincidir las claves entre tablas utilizando un hash o buscando a través de todo el set. Puede llamar a Estadísticas de actualización en toda la base de datos o solo en ciertas tablas o índices. Esto ralentiza la consulta de una ejecución a otra porque cuando las estadísticas están desactualizadas, es probable que el plan de consulta no sea óptimo para los datos recién insertados o modificados para la misma consulta (se explica más adelante). Puede no ser apropiado actualizar las estadísticas inmediatamente en una base de datos de Producción, ya que habrá algunos gastos generales, ralentización y retraso dependiendo de la cantidad de datos a muestra. También puede optar por utilizar un Análisis completo o un Muestreo para actualizar las estadísticas. Si observa el Plan de consulta, también puede ver las estadísticas de los índices en uso utilizando el comando DBCC SHOW_STATISTICS (tablename, indexname) . Esto le mostrará la distribución y los rangos de las claves en las que el plan de consulta está utilizando para basar su enfoque.

  2. BÚSQUEDA DE PARÁMETROS : El plan de consulta que se almacena en caché no es óptimo para los parámetros particulares que están pasando, a pesar de que la consulta en sí no ha cambiado. Por ejemplo, si pasa un parámetro que solo recupera 10 de las 1.000.000 filas, el plan de consulta creado puede usar una combinación Hash; sin embargo, si el parámetro que pasa usará 750.000 de las 1.000.000 filas, el plan creado puede ser un análisis de índice o de tabla. En tal situación, puede decirle a la instrucción SQL que use la opción OPCIÓN (RECOMPILE) o un SP para usar CON RECOMPILE. Para decirle al Motor esto es un " Single Usar Plan " y no usar un Plan en caché que probablemente no se aplique. No hay una regla sobre cómo tomar esta decisión, depende de conocer la forma en que los usuarios usarán la consulta.

  3. INDEXES - Es posible que la consulta no haya cambiado, pero un cambio en otro lugar, como la eliminación de un índice muy útil, ha ralentizado la consulta.

  4. ROWS CHANGED - Las filas que está consultando cambian drásticamente de una llamada a otra. Por lo general, las estadísticas son actualizado automáticamente en estos casos. Sin embargo, si está creando SQL dinámico o llamando a SQL dentro de un bucle cerrado, existe la posibilidad de que esté utilizando un Plan de consulta obsoleto basado en el número drástico incorrecto de filas o estadísticas. De nuevo en este caso LA OPCIÓN (RECOMPILAR) es útil.

  5. LA LÓGICA Es la Lógica, su consulta ya no es eficiente, estaba bien para un pequeño número de filas, pero ya no escala. Esto generalmente implica un análisis más profundo de la Plan de Consulta. Por ejemplo, ya no puedes hacer cosas a granel, sino que tienes que fragmentar las cosas y hacer confirmaciones más pequeñas, o tu Producto cruzado estaba bien para un conjunto más pequeño pero ahora ocupa CPU y Memoria a medida que se escala más grande, esto también puede ser cierto para usar DISTINCT, estás llamando a una función para cada fila, tus coincidencias de clave no usan un índice debido a la conversión de tipo de FUNDICIÓN o NULOS o funciones... Hay demasiadas posibilidades aquí.

En general, cuando escribe una consulta, debe tener alguna imagen mental de aproximadamente cómo se distribuyen ciertos datos dentro de su tabla. Una columna, por ejemplo, puede tener un número distribuido uniformemente de valores diferentes, o puede ser sesgada, el 80% de las veces tiene un conjunto específico de valores, ya sea que la distribución varíe con frecuencia con el tiempo o sea bastante estática. Esto le dará una mejor idea de cómo construir una consulta eficaz. Pero también cuando el rendimiento de la consulta de depuración tienen una base para construir una hipótesis de por qué es lento o ineficiente.

 119
Author: CodeCowboyOrg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-12 21:32:50

Para agregar a la excelente lista (dada por @ CodeCowboyOrg) de situaciones donde la OPCIÓN (RECOMPILE) puede ser muy útil,

  1. Variables de la tabla . Cuando se utilizan variables de tabla, no habrá estadísticas predefinidas para la variable de tabla, lo que a menudo conduce a grandes diferencias entre las filas estimadas y reales en el plan de consulta. El uso de la OPCIÓN (RECOMPILAR) en consultas con variables de tabla permite la generación de un plan de consulta que tiene una estimación mucho mejor de la fila números involucrados. Tuve un uso particularmente crítico de una variable de tabla que era inutilizable, y que iba a abandonar, hasta que agregué la OPCIÓN(RECOMPILAR). El tiempo de ejecución pasó de horas a solo unos minutos. Eso es probablemente inusual, pero en cualquier caso, si está utilizando variables de tabla y trabajando en la optimización, vale la pena ver si OPTION(RECOMPILE) hace una diferencia.
 22
Author: DWright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-20 20:20:35

Las primeras acciones antes de afinar las consultas es desfragmentar/reconstruir los índices y estadísticas, de otra manera estás perdiendo el tiempo.

Debe comprobar el plan de ejecución para ver si es estable (es el mismo cuando cambia los parámetros), si no, es posible que tenga que crear un índice de cobertura (en este caso para cada tabla) (sabiendo que el sistema puede crear uno que sea útil para otras consultas también).

Como ejemplo : crear índice idx01_datafeed_trans En datafeed_trans ( feedid, Fecha de alimentación) INCLUDE (acctNo, tradeDate)

Si el plan es estable o puede estabilizarlo, puede ejecutar la oración con sp_executesql('sql sentence') para guardar y usar un plan de ejecución fijo.

Si el plan es inestable, debe usar una instrucción ad-hoc o EXEC('sentencia sql') para evaluar y crear un plan de ejecución cada vez. (o un procedimiento almacenado "con recompile").

Espero que ayude.

 0
Author: Cristian Solervicéns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-23 12:49:54