存储过程 - 强制执行顺序

时间:2010-04-21 12:47:56

标签: sql-server tsql stored-procedures

我有一个存储过程,它本身按顺序调用其他存储过程的列表:

CREATE PROCEDURE [dbo].[prSuperProc]

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

但是,我的表中有时会产生一些奇怪的结果,由prProc2生成,这取决于prProc1生成的结果。如果我按顺序手动执行prProc1,prProc2,prProc3,那么一切都很好。看来,当我运行顶级过程时,在Proc1完成之前正在执行Proc2并将其结果提交给db。它并不总是出错,但是当Proc1的执行时间很长时(在这种情况下~10秒),它似乎出错了。

如何更改prSuperProc以使每个过程仅在前面的过程完成并提交后才执行?交易?

修改额外的详细信息:

我的数据库中有一个表,其中一列默认为null。 prProc1在此表上执行一组更新语句以填充此列。然后,prProc2根据此列中的值将摘要数据插入到辅助表中。

当我运行超级过程时,我(有时)看到的是第一个表具有由prProc1正确计算的结果,但是prProc2已经生成结果,好像该列全部为空。如果我然后手动运行prProc2,则会正确生成摘要数据。

3 个答案:

答案 0 :(得分:4)

Proc2将在Proc1之前运行:它很简单。 SQL将一个接一个地执行,但永远不会出现故障。

您可以使用TSQL_SPs template

对此进行分析

例如,你有2次执行包装器proc的运行吗?

答案 1 :(得分:2)

对于prSuperProc的每次调用,它们将以连续方式运行,1然后是下一个,然后是下一个。但是,如果多个用户都在调用prSuperProc,那么您将执行用户1的prProc1-prProc2 + prProc3和用户2的prProc1-prProc2 + prProc3的交错执行。

可能是这样的:

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

这实际上取决于您的程序中发生了什么,有多少并发用户以及他们正在更改和/或锁定哪些行

修改 你可以尝试这个来解决问题:

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

通过围绕所有事务使用事务,它将尝试锁定任何并发用户处理相同数据。使用TRY-CATCH将尝试捕获一个过程中可能发生的任何错误,并防止下一个过程运行。

答案 2 :(得分:2)

我遇到了同样的问题(当时正在维护产品)并且我通过取出最外层的proc并执行最顶层的proc来修复它。那个proc会执行依赖它的proc等等。它在B ***中很痛苦,但它确实有效。

HTH