SQL Server中使用复合键的存储过程中的ROWLOCK

时间:2016-03-21 16:04:58

标签: sql-server stored-procedures

已编辑:我有一个带有复合键的表,它被多个服务器上部署的多个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服务正在访问此表。

提前感谢您的帮助。

1 个答案:

答案 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。这将避免其他服务锁定,但这是一个数据库级别选项,因此您必须测试所有功能。其中大部分内容与以前相同,但有些场景需要测试(并发事务不会在以前被锁定的情况下被锁定)。

我不清楚:

  • 总行数中10000的百分比是多少?
  • 是否有聚集索引或者这是堆?
  • 选择和更新的实际执行计划是什么?
  • 什么是并发事务:插入或选择?
顺便提一下,发现了类似的问题: why the entire table is locked while "with (rowlock)" is used in an update statement