Plan de ejecución repentinamente lento para el proceso almacenado


15

Estoy tratando de entender un problema que tenemos con SQL Server 2000. Somos un sitio web moderadamente transaccional y tenemos un proceso almacenado llamado sp_GetCurrentTransactionsque acepta un ID de cliente y dos fechas.

Ahora, según las fechas y el cliente, esta consulta puede devolver cualquier cosa, desde cero hasta miles de filas.

El problema: lo que hemos experimentado es que de repente obtendremos una serie de errores (típicamente Execution Timeout Expiredo similares) para un cliente en particular mientras intentan ejecutar ese proceso almacenado. Así que examinamos la consulta, la ejecutamos en SSMS y descubrimos que tarda 30 segundos. Así que volvemos a compilar el proceso almacenado y -bang- ahora se ejecuta en 300 ms.

He hablado con nuestro DBA sobre esto. Me ha dicho que la base de datos creó un plan de consulta cuando creamos el proceso almacenado. Dijo que era un buen plan para ese conjunto de parámetros, pero si le arroja un cierto conjunto de parámetros, entonces el plan no será el mejor plan para esos datos, por lo que verá que se ejecuta lentamente.

Las opciones que se me presentan son mover esa consulta problemática desde un proceso almacenado y volver al SQL dinámico que tiene su plan de ejecución creado en cada ejecución.

Esto se siente como un paso atrás para mí y siento que debe haber una forma de evitar esto. ¿Hay alguna otra forma de lidiar con este problema?

Todas y cada una de las respuestas son apreciadas.


¿hay una declaración if / else en el proceso? He visto que esto sucede cuando el plan se almacena en caché en la instrucción if y luego intenta ejecutarse bajo el bloque else utilizando el plan incorrecto. ¿Corresponden estos errores con un cambio en el proceso?
Jeremy Gray

@ Jeremy: No hay cambios en el proceso y no hay más declaraciones / if.
Ciaran Archer

Respuestas:


14

Este problema se llama análisis de parámetros.

Las versiones posteriores de SQL Server le brindan más opciones para tratarlo, como OPTION (RECOMPILE)o OPTIMIZE FORsugerencias.

Puede intentar declarar variables en el procedimiento almacenado, asignar los valores de los parámetros a las variables y usar las variables en lugar de los parámetros, ya que parece que la mayoría de las veces obtiene un plan razonablemente satisfactorio.

Normalmente, los planes más catastróficamente malos son aquellos compilados para parámetros con muy alta selectividad pero ejecutados con parámetros con baja selectividad.

Suponiendo que el plan generado es más robusto con este enfoque y satisfactorio para todos los valores de los parámetros, la ventaja de este enfoque sobre lo sugerido por JNK es que no incurre en un costo de compilación por cada llamada.

La desventaja es que, para algunas ejecuciones, el tiempo de ejecución podría ser mayor que para un plan diseñado específicamente para esos valores de parámetros, por lo que es una compensación del tiempo de compilación frente al tiempo de ejecución.


3
O "echar un vistazo" en la terminología de Oracle
Gaius

Gracias @Gaius, es bueno saber la terminología de más de un RDBMS;)
Andrei Rînea

6

En lugar de utilizar SQL dinámico, siempre puede cambiar sus llamadas de proceso a:

EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE

Las WITH RECOMPILEfuerzas (¡lo adivinaste!) Una recompilación del plan de ejecución cada vez que se ejecuta.

También puede incluir WITH RECOMPILEen la definición del proceso almacenado:

CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...

2

También podría intentar decidir la base de datos que planea usar, aunque estaría luchando con el optimizador un poco, por lo que es más frágil de lo que esperaría.

La técnica es esta: divida el procedimiento almacenado en 2, uno destinado a un conjunto de parámetros, uno para otro. Agregue las cláusulas where a cada una de manera que entre ellas cubran todos los casos posibles. Mire los planes de consulta: uno debe estar optimizado para un conjunto de parámetros, el otro para el otro conjunto. Es posible que tenga que jugar con la consulta para que esto suceda, o esto puede no ser posible para su consulta, en cuyo caso este enfoque no funcionará.

Ahora haga que su procedimiento almacenado original verifique los valores de los parámetros y envíelo al uno de los dos procedimientos almacenados del párrafo anterior.

Esto puede funcionar, pero es una especie de truco para forzar al optimizador a trabajar de manera más efectiva para su consulta. Como todos estos hacks, en futuras versiones de la base de datos puede ser innecesario o incluso empeorar las cosas. Entonces, incluso si funciona, tienes que decidir si vale la pena.



0

Hmmm ... si nos centramos solo en este procedimiento almacenado, me sorprendería que el uso del plan de ejecución en caché podría causar el problema que está viendo. Solicitaría ver el plan de ejecución del procedimiento almacenado utilizando un conjunto de parámetros para el cliente y las dos fechas. Me pregunto si un índice más específico sería útil -> como en customerId, y solo en las dos fechas.


2
¿Por qué la sorpresa? la detección de parámetros es un problema bastante común con estos síntomas y parece que el DBA lo ha identificado como el problema.
Martin Smith

@MartinSmith: me sorprende un poco que el DBA que sabe sobre el olfateo de parámetros no sepa sobre las sugerencias de recompilación ...
JNK

@JNK - Eso es cierto. No estoy seguro de por qué no mencionarían eso.
Martin Smith

0

El rendimiento repentinamente degradante suena como un plan de consulta ineficiente que se produce, probablemente como resultado de estadísticas faltantes. Ejecute un generador de perfiles de SQL Server con las categorías de eventos "Errores y advertencias" establecidas y vea si hay advertencias sobre estadísticas faltantes.

También es posible que le falte un índice, o que necesite desfragmentar los índices, ya que pueden estar demasiado fragmentados para que SQL Server los use, lo que hace pensar que un Table Scan producirá menos E / S.

@JNK plantea un gran punto sobre los procesos almacenados: estos se compilan por adelantado y el plan de consulta se almacenará junto con el procedimiento almacenado.

No estoy necesariamente de acuerdo con el uso de WITH RECOMPILE, ya que luego pierde el beneficio de que el plan de consultas se almacene y reutilice. Hay algunos casos en que esto es necesario, es decir, si las estadísticas de distribución en las tablas subyacentes difieren mucho entre llamadas, pero generalmente, una vez que los datos en las tablas están maduros, la distribución de datos dentro de las tablas variará mínimamente.

Entonces, para resumir:

  1. Verificar estadísticas faltantes
  2. Comprobar la fragmentación del índice
  3. Crear y usar un proceso almacenado
  4. Cambie el nombre del proceso: sp_ es un espacio de nombres de prefijo reservado suavemente para los sistemas internos de SQL Server, lo que da como resultado que SQL Server siempre busque primero en la base de datos maestra esos procedimientos almacenados. Cambiar el nombre del proceso usp_ en lugar de sp_ dará como resultado un aumento del rendimiento, pero dudo que sea su problema en este caso.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.