El código crea un plan diferente cuando se ejecuta ad-hoc frente a un procedimiento almacenado

9

Tengo una declaración de eliminación que utiliza un plan incorrecto cuando se ejecuta dentro de un procedimiento almacenado, pero está eligiendo un plan mucho mejor cuando se ejecuta ad-hoc.

Reconstruí todos los índices de las tablas utilizadas por la consulta y eliminé todas las memorias caché. El optimizador aún elige el plan incorrecto para el procedimiento almacenado.

Me gustaría saber por qué el optimizador está utilizando un plan de ejecución diferente para el procedimiento almacenado en comparación con el SQL ad-hoc.

ACTUALIZACIÓN: supongo que deben haber sido los parámetros después de todo, cuando ejecuté el código ad-hoc con la variable codificada, puedo obtener el plan "incorrecto" con el valor correcto (es una fecha, valores que tienen un año de antigüedad parece generar el "buen" plan). Ahora trata de forzar el plan "bueno" en el proceso utilizando una sugerencia de consulta.

SOLUCIÓN: Terminé obteniendo el plan que quería usando la sugerencia OPTIMIZAR PARA DESCONOCIDO.

msgisme
fuente
Probablemente sea el olfateo de parámetros . ¿La consulta hace referencia a una variable en su WHEREcláusula?
Nick Chammas
44
¿Puede agregar código por favor
Gbn
También publique los planes en alguna parte, por favor. Como es, va a ser bastante difícil decirle exactamente por qué los planes son diferentes.
Aaron Bertrand
OK, más información: no puedo publicar los planes y códigos hasta que los ofusque un poco. Trataré de levantarlos en unos pocos. El plan para el procedimiento almacenado (incorrecto) realiza una exploración de índice agrupado de una tabla grande (todo, todas las particiones). Luego usa un bucle para buscar filas de una tabla más pequeña y luego elimina de la tabla más pequeña.
msgisme
El plan para el código ad-hoc (bueno) hace un escaneo de la tabla pequeña (que solo tiene 5-10 filas) y usa un índice no agrupado de la tabla grande para encontrar qué filas necesita verificar en el PK de la mesa grande. Intentaré obtener los planes reales tan pronto como pueda.
msgisme

Respuestas:

5

Sospechosos de siempre:

  1. constantes en adhoc, parámetros en código
  2. desajuste de los tipos de datos en el código
  3. olfateo de parámetros

Punto 1: el optimizador puede elegir el mejor plan para las constantes.
Cambiar las constantes = cambiar el plan. Un plen parametrizado es valioso

El punto 2 introducirá conversiones implícitas debido a la precedencia del tipo de datos,
por ejemplo, columna varchar en comparación con el parámetro nvarchar

Punto 3: use el enmascaramiento de parámetros u OPTIMIZAR PARA DESCONOCIDO
Editar: Para probar: ejecute el proceso almacenado, ejecute sp_updatestats, vuelva a ejecutar. Esto invalidará los planes almacenados en caché, lo que es mejor que borrar el caché del plan

Editar: después del comentario de jcolebrand

Puede deshabilitar el rastreo de varias maneras. Los 3 principales son

  • RECOMPILAR Esto es una tonta OMI.
  • OPTIMIZAR (sic) PARA DESCONOCIDO
  • Enmascaramiento de parámetros

Parámetro de enmascaramiento:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

El enmascaramiento y la sugerencia OPTIMIZE tienen el mismo efecto (tal vez por diferentes razones). Es decir, el optimizador tiene que usar estadísticas y distribución de datos ( Nota: todavía bajo prueba por Mark Storey-Smith ) evaluar los parámetros en sus propios méritos ? , en lugar de lo que fueron la última llamada. El optimizador puede recompilar o no. SQL Server 2005 agregó una recompilación de nivel de declaración para que haya menos impacto

Ahora, por qué un plan con parámetros "olfateados" es "rígido" en comparación con parámetros enmascarados / "desconocidos", no estoy seguro.

He usado el enmascaramiento de parámetros desde SQL Server 2000 para todo menos el código más simple. He notado que es probable que suceda con un código más complejo. Y en mi antiguo trabajo tengo algunos informes de informes que podrían cambiar los valores predeterminados de los parámetros del plan. Creo que el enfoque de "culto a la carga" fue más fácil que una llamada de soporte.

Edición 2, 12 de octubre de 2011, después de un chat

  • El enmascaramiento de parámetros y OPTIMIZAR PARA DESCONOCIDO tienen el mismo efecto por lo que puedo decir.
    La sugerencia es más limpia que el enmascaramiento, pero se agregó con SQL Server 2008.

  • El rastreo de parámetros ocurre en tiempo de compilación.
    WITH RECOMPILE genera un nuevo plan cada ejecución. Esto significa que una mala elección de los valores predeterminados influirá en el plan. En mi último trabajo, pude demostrarlo fácilmente con un código de informe: cambiar los valores predeterminados de los parámetros alteró el plan independientemente de los parámetros suministrados.

  • Este artículo de MS Connect es interesante: uso de índice subóptimo dentro del procedimiento almacenado (mencionado en una de las respuestas SO a continuación)

  • Bob Beauchemin también lo menciona

Cuestiones pendientes

  • ¿Todavía se aplica el olfateo con WITH RECOMPILE? Es decir, si el optimizador sabe descartar el plan, ¿tiene como objetivo la reutilización?

  • ¿Por qué los planes olfateados son "pegajosos"?

Enlaces de SO:

gbn
fuente
1. El parámetro en el sp es una variable en el código 2. Nuevamente, el mismo tipo de datos 3. He ejecutado ambos con una amplia variedad de parámetros, y obtengo el mismo plan cada vez. Limpié el caché después de cada intento.
msgisme
1
Re: punto 3. También puede ejecutar la declaración con OPTION (RECOMPILE)o todo el proceso WITH RECOMPILEpara obligar a SQL Server a ignorar los planes existentes.
Nick Chammas
3
Por cierto OPTIMIZE, porque Microsoft es una empresa estadounidense. :)
Nick Chammas
1
@Gbn ¿alguna idea sobre cómo prevenir / derrotar la detección de parámetros?
jcolebrand
1
@jcolebrand: la respuesta simple es "no" :-)
gbn
2

No olvide que la configuración ANSI que ha configurado para el plan de conexión desempeña un papel en la selección del plan de ejecución. Cuando la aplicación llama al procedimiento almacenado, probablemente tenga una configuración ANSI diferente a la de su conexión SSMS.

mrdenny
fuente