我有一个无法同时执行的存储过程。多个过程称此存储过程称为,但是该过程顺序访问存储过程至关重要。
存储过程基本上扫描了一个符合各种条件的主要键,将记录标记为通过调用过程中使用的记录,然后将主键传递回呼叫过程。
可以存在从一个到十几个实例的任何地方,具体取决于存在多少工作。
我决定通过在存储过程中使用sp_GetAppLock
来防止并发。我抓住一个独家交易锁,将@Resource
设置为仅在此存储过程中使用的字符串。该锁定唯一阻止的是执行此存储过程。
存储过程中的调用如下:
sp_getapplock @Resource='My Unique String Here'
,@LockMode='Exclusive' -- Type of lock
,@LockOwner='Transaction' -- Transaction or Session
,@LockTimeout = 5000
它可以游泳。如果我的过程中有十几个实例正在运行,则只有一个时间点执行存储过程,而其他11个则要等待,然后等待他们。
唯一的问题是我们的DBA。他是一个非常好的DBA,他不断监视数据库,以阻止并在超过一定阈值时收到警报。我对sp_getapplock
的使用触发了很多警报。我的DBA声称自己自身的阻塞是一个性能问题。
他的主张准确吗?我的感觉是,这是"好"的阻塞,因为唯一被阻止的是执行存储过程,而我想要将被阻止。但是我的DBA说,强迫SQL Server强制执行此阻塞是对资源的重大消耗。
我可以告诉他"放下裂缝管",就像我们以前所说的那样?还是我应该重写我的应用程序以避免需要sp_getapplock
?
我阅读的文章在sp_getapplock
上卖给我的文章在这里:sp_getapplock
不幸的是,我认为您的DBA有一个要点,阻止确实会消耗资源,并且这种阻止正在为服务器添加额外的负载。
让我解释如何:
-
proc被调用,SQL Server从线程池分配工作线程,并开始执行。
-
呼叫2,3,4,...进来,SQL Server再次分配了这些呼叫的Worker线程,线程开始执行在
"Waiting List"
中以获取资源可用。 -
由于您的流程而持有的任何SQL服务器的数字非常有限的工作线程。
-
现在,由于开发人员决定这样做,SQL Server正在累积等待。
作为DBA,我们希望您来到SQL Server获得所需的东西,并尽快留下它。如果您有意呆在那里,坚持资源并将SQL Server承受压力,它将惹恼DBA。
我认为您需要重新考虑应用程序设计并提出替代解决方案。
也许是SQL Server中的"过程表",在过程启动时使用某些值更新,并且每个呼叫首先检查过程表,然后再发射该Proc的下一个呼叫。因此,等待内容发生在应用程序层中,并且只有在资源可用时才发生,然后转到DB。
" 存储过程基本上扫描了一个符合各种条件的主键,将记录标记为通过调用过程中使用的记录,然后将主键传递给后键到呼叫过程。">
这是在SP中进行的另一种方法:
BEGIN TRANSACTION
SELECT x.PKCol
FROM dbo.[myTable] x WITH (FASTFIRSTROW XLOCK ROWLOCK READPAST)
WHERE x.col1 = @col1...
IF @@ROWCOUNT > 0 BEGIN
UPDATE dbo.[myTable]
SET ...
WHERE x.col1 = @col1
END
COMMIT TRANSACTION
xlock 指定要拿走并保留独家锁,直到交易完成为止。如果用Rowlock,Paglock或Tablock指定,则独家锁适用于适当的粒度水平。