SQL在查询中使用UPDLOCK在过滤和排序表后更新前1条记录

时间:2015-12-04 18:26:17

标签: sql-server

我有一个存储过程如下:

CREATE PROCEDURE [dbo].[RV_SM_WORKITEM_CHECKWORKBYTYPE] 
( 
    @v_ServiceName Nvarchar(20)
    ,@v_WorkType Nvarchar(20)
    ,@v_WorkItemThreadId nvarchar(50)
) 
AS BEGIN
    ;WITH updateView AS 
    (
        SELECT TOP 1 * 
        FROM rv_sm_workitem WITH (UPDLOCK) 
        WHERE stateofitem = 0 
          AND itemtype = @v_worktype 
        ORDER BY ITEMPRIORITY
    )
    UPDATE updateView
    SET assignedto = @v_ServiceName, 
        stateofitem = 1, 
        dateassigned = getdate(), 
        itemthreadid = @v_WorkItemThreadId
    OUTPUT INSERTED.* 
END

它完成了我需要它做的工作,即获取具有最高优先级的1条记录,将其状态从Available(0)更改为Not-Available(1),并返回要完成的工作记录。我应该能够有很多线程(20个以上)使用这个proc并让所有20个线程不断运行/抓取一个新的工作项目。但是我发现超过2个线程,添加线程正在等待锁;我猜测UPDLOCK正在造成这种情况。

我有两个问题,有更好的方法吗?

我可以在没有cte中的UPDLOCK的情况下执行此操作,因为默认情况下update语句使用UPDLOCK吗?请注意,在任何给定时间,此表中都有超过400,000条记录。

1 个答案:

答案 0 :(得分:0)

我必须做类似的事情,这就是我的建议:

AS BEGIN
  DECLARE @results table (id int, otherColumns varchar(50))
  WHILE (EXISTS(SELECT TOP 1 * FROM @results))
  BEGIN
    ;WITH updateView AS 
    (
        SELECT TOP 1 * 
        FROM rv_sm_workitem
        WHERE stateofitem = 0 
          AND itemtype = @v_worktype 
        ORDER BY ITEMPRIORITY
    )
    UPDATE updateView
    SET assignedto = @v_ServiceName, 
        stateofitem = 1, 
        dateassigned = getdate(), 
        itemthreadid = @v_WorkItemThreadId
    OUTPUT INSERTED.* into @results
    where stateofitem = 0
 END
END

这可确保调用不允许对项进行双重处理。 (因为update语句中的where子句)。

这个想法有其他变化,但这是传达它的简单方法。这不是生产就绪代码,因为它会在while循环中不断循环,直到有东西要处理。但我留给你决定如何突破或不循环并返回空(并让客户端代码处理它。)

以下是我遇到此问题时帮助我的answer