2009-06-18 16 views
8

Un cliente ha informado de instancias repetidas de Comportamiento muy extraño al ejecutar un procedimiento almacenado.MS SQL Server 2005 - Procedimiento almacenado "Interrupciones espontáneas"

Tienen código que se ejecuta en una transposición en caché de un conjunto de datos volátil. Un procedimiento almacenado fue escrito para volver a procesar el conjunto de datos sobre la demanda si:
1. El conjunto de datos ha cambiado desde la última reprocesamiento
2. El datset ha permanecido inalterada durante 5 minutos

(La segunda condición se detiene el nuevo cálculo repetido masiva durante tiempos de cambio.)


Esto funcionó bien durante un par de semanas, el SP estaba tomando 1-2 segundos para completar la re-procesamiento, y sólo lo hicieron cuando sea necesario. Entonces ...

  • El SP pronto "dejó de funcionar" (que sólo siguió corriendo y nunca regresó)
  • Nos cambió el SP de una manera sutil y funcionó de nuevo
  • Unos días más tarde se detuvo a trabajar de nuevo
  • Alguien dijo entonces "hemos visto esto antes, simplemente volver a compilar el SP"
  • sin ningún cambio en el código que vuelve a compilar el SP, y funcionó
  • pocos días después que dejó de funcionar de nuevo


Esto se ha repetido muchas, muchas veces. El SP de repente "deja de funcionar", nunca regresa y el cliente agota el tiempo de espera. (Intentamos ejecutarlo a través de Management Studio y cancelamos la consulta después de 15 minutos.)

Sin embargo, cada vez que recompilamos el SP, de repente funciona de nuevo.

Todavía no he probado WITH RECOMPILE en las declaraciones apropiadas de EXEC, pero particularmente no quiero hacerlo de ninguna manera. Se llama cientos de veces por hora y normalmente no hace nada (solo reprocesa los datos unas pocas veces al día). Si es posible quiero evitar la sobrecarga de volver a compilar lo que es un SP relativamente complicado "sólo para evitar algo, que 'no debe' suceder ...


  • Alguien ha experimentado esto antes?
  • ¿alguien tiene alguna sugerencia sobre cómo superarlo?


Cheers,
Dems.


EDIT:

El código pseduo sería como sigue:

  • lectura "a" de table_x
  • leer "b" de table_x
  • Si (a < b) devuelve
  • iniciar la transacción
  • BORRAR table_y
  • INSERT INTO table_y < 3 selecciona unioned juntos>
  • ACTUALIZACIÓN table_x
  • confirmar la transacción

Los selecciona "no son bastante", pero cuando se ejecutan en línea ejecutan en poco tiempo. Incluyendo cuando el SP se niega a completar. Y el generador de perfiles muestra que es el INSERTO en el que el SP "bloquea"

No hay parámetros para el SP, y sp_lock no muestra nada que bloquee el proceso.

+2

Me parece que tiene una transacción que no está siendo comprometida o revertida. Difícil de decir sin ver el código. – Juliet

+0

Ah, y nunca está de más descargar los últimos service packs y ups. – Juliet

+0

Debe ser un BLOQUEO, o al menos se comporta así ... – tekBlues

Respuesta

1

Como han dicho otros, algo acerca de la forma en que los datos o las estadísticas de la tabla fuente están cambiando está causando que el plan de consulta en caché se quede obsoleto.

WITH RECOMPILE probablemente sea la solución más rápida: use SET STATISTICS TIME ON para averiguar cuál es realmente el costo de recompilación antes de descartarlo de forma inmediata.

Si aún no es una solución aceptable, la mejor opción es probablemente tratar de refactorizar la instrucción de inserción.

No dice si está utilizando UNION o UNION ALL en su declaración de inserción. He visto INSERT INTO con UNION producen algunos planes de consulta extrañas, sobre todo en las versiones anteriores a SP2 de SQL 2005.

  • sugerencia de abandonar y recrear la tabla de destino con SELECT INTO de Raj es un camino a seguir.

  • También puede probar la selección de cada uno de los tres consultas de origen en su propia tabla temporal, entonces UNION esas tablas temporales juntos en el inserto.

  • Alternativamente, usted podría tratar de una combinación de estas sugerencias - poner los resultados de la unión en una tabla temporal con SELECT INTO, continuación, introducir información de que en el objetivo mesa.

He visto todos estos enfoques resolver problemas de rendimiento en escenarios similares; las pruebas revelarán cuál da los mejores resultados con los datos que tiene.

3

Esta es la huella del parámetro-sniffing. Sí, el primer paso es intentar RECOMPRA, aunque no siempre funciona de la manera que desea en 2005.

Actualización: Intentaría recompilar a nivel de declaración de todos modos ya que esto podría ser una estadística problema (oh sí, verifique que la actualización automática de estadísticas esté activada).

Si esto no parece ajustarse a la detección de parámetros, entonces compare el plan de consulta real desde cuándo funciona correctamente y desde cuándo se ejecuta para siempre (utilice el plan estimado si no puede obtener el real, aunque real es mejor). Está buscando ver si el plan cambia o no.

+0

Desafortunadamente, no hay parámetros. La única variable es el contenido del conjunto de datos de origen que se procesa. – MatBailie

3

Estoy totalmente de acuerdo con el diagnóstico de detección de parámetros. Si tiene parámetros de entrada para el SP que varían (o incluso si no varían), asegúrese de enmascararlos con una variable local y usar la variable local en el SP.

También puede usar WITH RECOMPILE si el conjunto está cambiando pero el plan de consulta ya no sirve.

En SQL Server 2008, puede usar la característica OPTIMIZE FOR UNKNOWN.

Además, si su proceso implica rellenar una tabla y luego usar esa tabla en otra operación, recomiendo dividir el proceso en SP separados y llamarlos individualmente WITH RECOMPILE. Creo que los planes generados al principio del proceso a veces pueden ser muy pobres (tan deficientes como para no completarse) cuando se completa una tabla y luego se usan los resultados de esa tabla para llevar a cabo una operación. Porque en el momento del plan inicial, la tabla era muy diferente a la que tenía después de la inserción inicial.

+0

Sin parámetros y los cambios en el conjunto de datos son sutiles, no significativos. El plan de ejecución no debería tener que cambiar en absoluto. Lo que lo hace tan confuso. Es como si el plan de ejecución cambiara cuando no debería, como estadísticas corruptas. ¡Pero también los revisamos! * suspiro * – MatBailie

+0

He agregado algunas notas sobre procesos largos que usan varias tablas para resultados intermedios. –

+0

En este caso, no hay pasos intermedios. Solo un DELETE y luego un INSERT, la ACTUALIZACIÓN a la que se hace referencia en el pseudo código solo está ingresando GetDate() en una tabla de control de metadatos. – MatBailie

0

Obviamente, cambiar el procedimiento almacenado (recompilando) cambia las circunstancias que llevaron al bloqueo.

Intente registrar el progreso de su SP como se describe here o here.

0

Si usted está haciendo estos pasos:

DELETE table_y 
INSERT INTO table_y <3 selects unioned together> 

Es posible que desee probar este lugar

DROP TABLE table_y 
SELECT INTO table_y <3 selects unioned together> 
+0

Creo que se refiere a TRUNCATE TABLE en lugar de DROP TABLE. Además, el contexto de seguridad que invoca el procedimiento almacenado no puede TRONCATE la tabla, solo funciona DELETE. Además, es el INSERT ese el problema, no la eliminación de los datos. – MatBailie

+0

Pero el hecho de que los datos cambien a la mitad del lote significa que el plan de ejecución elegido al principio del lote podría ser deficiente, de ahí mi intención de obtener mejores planes de ejecución por partes. –

0

Estoy de acuerdo con la respuesta dada anteriormente en un comentario, esto suena como una transacción no cerrada, especialmente si todavía puede ejecutar la declaración de selección del analizador de consultas.

Suena como si hubiera una transacción abierta con una eliminación pendiente para table_y y la inserción no puede suceder en este punto.

Cuando su SP se bloquea, ¿puede realizar una inserción en table_y?

+0

El único código que alguna vez escribe en esa tabla es el SP en cuestión. Como el código es BEGIN TRANSACTION, ELIMINAR

, INSERT INTO
, UPDATE , COMMIT TRANSACTION No puedo ver dónde podría surgir el escenario descrito. Especialmente porque sp_lock no muestra ninguna contención de bloqueo. – MatBailie

+1

Acaba de salir de interés, ¿qué sucede si este procedimiento se ejecuta dos veces, mientras el primer procedimiento todavía se está ejecutando? – Paddy

0

¿Tiene un trabajo de mantenimiento de índice?

¿Están sus estadísticas actualizadas? Una forma de saberlo es examinar los planes de consulta reales y estimados para grandes variaciones.

+0

IBM posee el rollo de DBA para todas las instancias de SQL SERVER del cliente. Los índices se mantienen en un proceso nocturno. Tendré que verificar los planes ACTUAL y ESTIMADO cuando esté funcionando, y luego verificar el ESTIMADO cuando esté 'roto'. No puedo obtener el ACTUAL cuando está roto ya que aparentemente nunca regresa. Y, no, no podemos dejar una mesa bloqueada durante horas esperando que vuelva a funcionar en un sistema en vivo :) – MatBailie

0

Como han dicho otros, es muy probable que se trate de una transacción no confirmada.

Mi mejor conjetura:

Usted querrá asegurarse de que table_y se pueden eliminar por completo y rápidamente.

Si hay otros procedimientos almacenados o piezas de código externo que alguna vez contengan transacciones en esta tabla, es posible que esté esperando por siempre. (Pueden salirse y nunca cerrar la transacción)

Otra nota: intente utilizar truncar si es posible. que utiliza menos recursos de un borrado, sin cláusula where:

truncate table table_y 

Además, una vez que ocurre un error dentro de su propia transacción, que hará que todas las llamadas siguientes (cada 5 minutos aparentemente) a "colgar", a menos que se resuelva su error:

begin tran 
begin try 
-- do normal stuff 
end try 
begin catch 
rollback 
end catch 
commit 

El primer error es lo que le dará información sobre el error real. Verlo colgado en tus propias pruebas posteriores es solo un efecto secundario.

Cuestiones relacionadas