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

问题描述 投票:2回答:3

我们有以下情况:

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

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

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

最好的祝福

sql sql-server stored-procedures
3个回答
1
投票

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

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


1
投票

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

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

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

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

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

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

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'

0
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.