已编辑:我有一个带有复合键的表,它被多个服务器上部署的多个Windows服务使用。
列:
UserId (int) [CompositeKey],
CheckinTimestamp (bigint) [CompositeKey],
Status (tinyint)
此表中将连续插入。我希望我的Windows服务选择前10000行并进行一些处理,同时仅锁定这10000行。我正在使用ROWLOCK使用以下存储过程:
ALTER PROCEDURE LockMonitoringSession
AS
BEGIN
BEGIN TRANSACTION
SELECT TOP 10000 * INTO #TempMonitoringSession FROM dbo.MonitoringSession WITH (ROWLOCK) WHERE [Status] = 0 ORDER BY UserId
DECLARE @UserId INT
DECLARE @CheckinTimestamp BIGINT
DECLARE SessionCursor CURSOR FOR SELECT UserId, CheckinTimestamp FROM #TempMonitoringSession
OPEN SessionCursor
FETCH NEXT FROM SessionCursor INTO @UserId, @CheckinTimestamp
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE dbo.MonitoringSession SET [Status] = 1 WHERE UserId = @UserId AND CheckinTimestamp = @CheckinTimestamp
FETCH NEXT FROM SessionCursor INTO @UserId, @CheckinTimestamp
END
CLOSE SessionCursor
DEALLOCATE SessionCursor
SELECT * FROM #TempMonitoringSession
DROP TABLE #TempMonitoringSession
COMMIT TRANSACTION
END
但是,通过这样做,dbo.MonitoringSession
将被永久锁定,直到存储过程结束。我不确定我在这里做错了什么。
此存储过程的唯一目的是选择并更新10000个没有任何主键的最近行,并确保整个表未被锁定,因为多个Windows服务正在访问此表。
提前感谢您的帮助。
答案 0 :(得分:0)
(不是答案,但评论时间太长)
目的描述应该是关于为什么/更新整个表的内容。您的SP用于更新Status=0
的所有行以设置Status=1
。因此,当您的某个服务决定运行此SP时 - 所有行都变得不相关。我的意思是,逻辑上导致状态发生变化的事件已经发生,您只需要一些时间在数据库中进行物理更改。那么为什么你想让其他服务读取不相关的行呢?好的,可能你需要读取可用于读取的行(未更改) - 但由于您正在更新整个表,因此不能再次清楚了。
您可以使用READPAST
提示跳过锁定的行,并且您需要使用行锁。
好的,但是即使处理前N行,使用一个语句更新那些N行也会比循环遍历这些行要快得多。你手动做同样的工作。
查看合并UPDLOCK
+ READPAST
以使用并行流程处理相同队列的示例:https://www.mssqltips.com/sqlservertip/1257/processing-data-queues-in-sql-server-with-readpast-and-updlock/
小提示 - CURSOR STATIC, READONLY, FORWARD_ONLY
与存储到临时表的内容相同。查看STATIC
选项:
https://msdn.microsoft.com/en-us/library/ms180169.aspx
另一件事是建议考虑RCSI。这将避免其他服务锁定,但这是一个数据库级别选项,因此您必须测试所有功能。其中大部分内容与以前相同,但有些场景需要测试(并发事务不会在以前被锁定的情况下被锁定)。
我不清楚: