我们如何避免并行执行存储过程?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我们如何避免并行执行存储过程?相关的知识,希望对你有一定的参考价值。
我们有以下情况:
存储过程由中间件调用,并作为参数提供XML文件。然后,过程解析XML文件并将值插入循环内的临时表中。循环后,临时表中的值将插入到物理表中。
问题是,存储过程具有相对较长的运行时间(约5分钟)。在此期间,可能是第二次调用它,这将导致两个进程被暂停。
现在我的问题是:如果存储过程已经在运行,我们如何避免再次执行存储过程?
最好的祝福
存储过程也意味着多次并行运行。我们的想法是重用代码。如果要避免多次运行相同的输入,则需要手动处理。通过对输入实施条件检查或使用某种锁定机制。
如果您不希望您的过程完全并行运行(无论输入如何),最佳策略是使用DB表中的某些条目获取锁定,或者根据您使用的DBMS使用全局变量。
我建议您设计应用程序层,以防止同时运行此进程的多个实例。例如,您可以将逻辑移动到一次处理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'
您可以使用exec sp_who2检查存储过程是否已在运行。这可能是一种考虑的方法。在您的SP中,首先检查它,如果是,则直接退出。它会在下次执行作业时再次运行。
您需要过滤掉当前线程,确保该SP的计数为1(1表示当前进程,2表示已经运行),或者具有首先调用的辅助SP。
以下是其他想法:Check if stored procedure is running
以上是关于我们如何避免并行执行存储过程?的主要内容,如果未能解决你的问题,请参考以下文章