2010-04-21 16 views
5

tengo un procedimiento almacenado que se denomina de una lista de otros procedimientos almacenados en orden:procedimiento almacenado - forzando orden de ejecución

CREATE PROCEDURE [dbo].[prSuperProc] 

AS 
BEGIN 
    EXEC [dbo].[prProc1] 
    EXEC [dbo].[prProc2] 
    EXEC [dbo].[prProc3] 
    --etc 
END 

Sin embargo, a veces tienen algunos resultados extraños en mis tablas, generados por prProc2, que depende de los resultados generados por prProc1. Si ejecuto prProc1, prProc2, prProc3 manualmente, entonces todo está bien. Parece que cuando ejecuto el procedimiento de nivel superior, ese Proc2 se está ejecutando antes de que Proc1 se haya completado y haya confiado sus resultados a la base de datos. No siempre sale mal, pero parece ir mal cuando Proc1 tiene un tiempo de ejecución largo (en este caso ~ 10s).

¿Cómo modifico prSuperProc de manera que cada procedimiento solo se ejecuta una vez que se ha completado y confirmado el procedimiento anterior? ¿Actas?

Editar para el detalle adicional:

Hay una mesa en mi db que tiene una columna que es nulo por defecto. prProc1 realiza un conjunto de instrucciones de actualización en esta tabla para rellenar esta columna. Luego, prProc2 inserta datos de resumen en una tabla secundaria en función de los valores de esta columna.

Cuando ejecuto el procedimiento súper, lo que estoy viendo (a veces) es que la primera tabla tiene los resultados calculados correctamente por prProc1, pero prProc2 ha generado resultados como si la columna fuera nula. Si luego ejecuto prProc2 manualmente, los datos de resumen se generan correctamente.

Respuesta

4

Proc2 no ejecutar antes de Proc1: es así de simple. SQL se ejecutará uno después del otro, pero nunca fuera de servicio.

puede perfilar esto usando el TSQL_SPs template

¿Tiene 2 ejecuciones de la envoltura proc en marcha, por ejemplo?

+1

Estoy seguro de que el envoltorio proc solamente se ejecuta una vez en cualquier momento - que sólo es utilizado por mí en este momento! No estoy sugiriendo que se estén agotando, solo que las actualizaciones realizadas por Proc1 no se han confirmado por completo cuando se inicia Proc2, y he confirmado esto ejecutándolas manualmente para eliminar el error. – meepmeep

+0

@meepmeep, agregue las sentencias de tipo 'PRINT 'starting prProc1'' y' PRINT' end prProc1'' en todos estos procedimientos (incluido el wrapper) y luego en SSMS ejecute 'EXEC [dbo]. [PrSuperProc]', con parámetros entonces Proc1 tiene un tiempo de ejecución largo (en este caso ~ 10s) para ver qué sucede. –

+0

He introducido esto. Como siempre, el error se niega a repetirse, por lo que voy a dejar esta Q abierta hasta que vuelva a suceder y ver qué resultados. ¡Gracias! – meepmeep

2

Para cada llamada de prSuperProc, se ejecutarán en serie, 1 luego la siguiente y luego la siguiente. Sin embargo, si varios usuarios están llamando al prSuperProc, entonces tendrá una ejecución intercalada de prProc1-prProc2 + prProc3 del usuario 1 y prProc1-prProc2 + prProc3 del usuario 2.

que podría ser algo como esto:

user1 calls prSuperProc 
user1   prProc1 is called 
user2 calls prSuperProc 
user1   prProc2 is called 
user2   prProc1 is called 
user1   prProc3 is called 
user2   prProc2 is called 
user2   prProc3 is called 

que realmente depende de lo que está pasando dentro de sus procedimientos, el número de usuarios concurrentes, y qué filas están cambiando y/o bloqueo

EDITAR puede probar esto a solucionar el problema:

CREATE PROCEDURE [dbo].[prSuperProc] 

AS 
BEGIN TRY 
    BEGIN TRANSACTION 
    EXEC [dbo].[prProc1] 
    EXEC [dbo].[prProc2] 
    EXEC [dbo].[prProc3] 
    --etc 
    COMMIT 
END TRY 
BEGIN CATCH 
    IF XACT_STATE()!=0 
    BEGIN 
     ROLLBACK TRANSACTION 
    END 

    SELECT 
     ERROR_NUMBER() AS ErrorNumber 
     ,ERROR_SEVERITY() AS ErrorSeverity 
     ,ERROR_STATE() AS ErrorState 
     ,ERROR_PROCEDURE() AS ErrorProcedure 
     ,ERROR_LINE() AS ErrorLine 
     ,ERROR_MESSAGE() AS ErrorMessage 


    --will echo back the complete original error message 
    DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int 
    SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE() 
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine) 

END CATCH 
GO 

mediante el uso de un TRANSACTIO n alrededor de todo, intentará bloquear a los usuarios simultáneos para que no trabajen en los mismos datos. El uso de TRY-CATCH intentará detectar cualquier error que pueda ocurrir en un procedimiento y evitar que los siguientes se ejecuten.

1

Tuve el mismo problema (era mantener un producto en ese momento) y lo solucioné eliminando el proceso más externo y ejecutando la mayor parte del proceso. Entonces ese proceso ejecutaría el proceso dependiente de él y así sucesivamente. Es un dolor en el B *** pero funciona.

HTH

+0

gracias - Voy a intentar las transacciones a continuación, pero si eso falla, entonces esto funciona como una solución no elegante. También quiero poder ejecutar los procesos de forma independiente, así que tendré que agregar algún tipo de parámetro que se conecte en cascada a través de las llamadas de proceso. – meepmeep

Cuestiones relacionadas