我有一个无法同时执行的存储过程。多个进程调用此存储过程,但进程按顺序访问存储过程至关重要。
存储过程基本上扫描表以查找满足各种条件的主键,将记录标记为调用进程正在使用,然后将主键传递回调用进程。
根据存在的工作量,可能存在一到十几个调用过程的实例。
我决定在存储过程中使用sp_GetAppLock
来防止并发。我获取了一个独占事务锁,@Resource
设置为仅在此存储过程中使用的字符串。此锁定唯一阻止的是执行此存储过程。
存储过程中的调用如下所示:
sp_getapplock @Resource='My Unique String Here'
,@LockMode='Exclusive' -- Type of lock
,@LockOwner='Transaction' -- Transaction or Session
,@LockTimeout = 5000
它可以游泳。如果我的进程的十几个实例正在运行,则只有其中一个实例在任何一个时间点执行存储过程,而另外一个实例排队并等待轮到他们。
唯一的问题是我们的DBA。他是一名非常优秀的DBA,他不断监视数据库的阻塞情况,并在超过某个阈值时收到警报。我对sp_getapplock
的使用触发了很多警报。我的DBA声称阻止内在和自身是一个性能问题。
他的说法准确吗?我的感觉是,这是“好”阻止,因为唯一被阻止的是执行存储过程,并且想要被阻止。但我的DBA表示,强制SQL Server强制执行此阻止是一种重要的资源消耗。
我可以告诉他“按下裂缝管”,就像我们常说的那样吗?或者我应该重新编写我的应用程序以避免需要sp_getapplock
?
我在sp_getapplock
上看到的卖给我的文章在这里:sp_getapplock
答案 0 :(得分:1)
不幸的是,我认为你的DBA有一点,阻塞会耗尽资源,而这种类型的阻塞会给服务器带来额外的负担。
让我解释一下:
Proc被调用,SQL Server将工作线程从线程池分配给它,它开始执行。
调用2,3,4,...进来,SQL Server再次为这些调用分配工作线程,线程开始执行,但由于你获得了独占锁,所有线程都被挂起并坐着在"Waiting List"
中获取资源。
由于您的进程,正在保留任何SQL Server上数量非常有限的工作线程。
现在SQL Server正在积累等待,因为开发人员决定这样做。
作为一名DBA,我们希望您来SQL Server获取所需内容并尽快保留。如果你故意呆在那里并持有资源并使SQL Server承受压力,那么它会让DBA感到厌烦。
我认为您需要重新考虑您的应用程序设计并提出替代解决方案。
可能是SQL Server中的“进程表”,当进程启动时为每个调用更新一个值,并在触发该proc的下一个调用之前先检查进程表。因此,等待事件发生在应用程序层中,并且只有在资源可用时才会转到数据库。
答案 1 :(得分:1)
“ 存储过程基本上是在表中扫描满足各种条件的主键,将记录标记为正在由调用过程使用,然后将主键传递回调用过程。“
这是在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指定,则排他锁适用于适当的粒度级别。