我们如何避免并行执行存储过程?

时间:2018-03-06 08:34:18

标签: sql sql-server stored-procedures

我们有以下情况:

存储过程由中间件调用,并作为参数提供XML文件。然后,过程解析XML文件并将值插入循环内的临时表中。循环后,临时表中的值将插入到物理表中。

问题是,存储过程的运行时间相对较长(大约5分钟)。在此期间,很可能是第二次调用它,这将导致两个进程被暂停。

现在我的问题: 如果存储过程已经在运行,我们如何避免再次执行存储过程?

祝你好运

3 个答案:

答案 0 :(得分:1)

存储过程也应该多次并行运行。我们的想法是重用代码。 如果要避免多次运行相同的输入,则需要手动处理。通过对输入进行条件检查或使用某种锁定机制。

如果您不希望您的程序完全并行运行(无论输入如何),最好的策略是使用DB表中的某些条目获取锁定,或者根据您使用的DBMS使用全局变量。

答案 1 :(得分:1)

我建议您设计应用层,以防止此过程的多个实例一次运行。例如,您可以将逻辑移动到一次处理1条消息的队列中。另一种选择是在应用程序级别锁定以防止执行数据库调用。

SQL Server确实有一个锁定机制来确保代码块不会多次运行:" app lock"。这在概念上类似于C#中的lock语句或您在其他语言中可能看到的其他信号量。

要获取应用程序锁定,请致电sp_getapplock。例如:

begin tran
exec sp_getapplock @Resource = 'MyExpensiveProcess', @LockMode = 'Exclusive', @LockOwner = 'Transaction'

如果另一个进程获得了锁定,此调用将阻止。如果第二个RPC调用尝试运行此过程,并且您希望该过程返回有用的错误消息,则可以传入@LockTimeout 0并检查返回码。

例如,如果无法获取锁定,则下面的代码会引发错误。您的代码可以返回应用程序解释为“#34;进程已经在运行的其他内容”,稍后再试一次":

begin tran
declare @result int
exec @result = sp_getapplock @Resource = 'MyExpensiveProcess', @LockMode = 'Exclusive', @LockOwner = 'Transaction', @LockTimeout = 0

if @result < 0
begin
    rollback
    raiserror (N'Could not acquire application lock', 16, 1)
end

要解除锁定,请致电sp_releaseapplock

exec sp_releaseapplock @Resource = 'MyExpensiveProcess'

答案 2 :(得分:0)

您可以使用exec sp_who2检查存储过程是否已在运行。这可能是一种考虑的方法。在您的SP中,首先检查它,如果是,则直接退出。它将在下次执行作业时再次运行。

您需要过滤掉当前线程,确保该SP的计数为1(1表示当前进程,2表示已经运行),或者有一个首先调用的辅助SP。

以下是其他想法:Check if stored procedure is running