当WITH (NOLOCK) 使用内部游标时,存储过程挂起

nwG*_*ham 2 sql-server stored-procedures sql-server-2008

我在 SQL Server 2008 R2 中有一个存储过程,如下所示;

DECLARE @uniqueId BIGINT

DECLARE TestCursor CURSOR FOR 
    SELECT em.uniqueId 
    FROM EMPLYEE_MASTER em WITH (NOLOCK)
    INNER JOIN EMP_DETAILS edt WITH (NOLOCK) ON em.uniqueId = edt.uniqueId
    INNER JOIN EMP_ATTENDANCE ea WITH (NOLOCK) ON em.uniqueId = ea.uniqueId

OPEN TestCursor

FETCH NEXT FROM TestCursor INTO @uniqueId

WHILE @@fetch_status = 0
BEGIN
    BEGIN TRANSACTION  purge        

    DELETE FROM EMPLYEE_MASTER where uniqueId = @uniqueId
    DELETE FROM EMP_DETAILS where uniqueId = @uniqueId
    DELETE FROM EMP_ATTENDANCE where uniqueId = @uniqueId

    DELETE FROM EMP_ADDRESS where uniqueId = @uniqueId
    DELETE FROM EMP_APPRAISALS where uniqueId = @uniqueId

    COMMIT TRANSACTION purge

    FETCH NEXT FROM TestCursor INTO @uniqueId
END

CLOSE TestCursor
DEALLOCATE TestCursor
Run Code Online (Sandbox Code Playgroud)

该存储过程在开始运行时会挂起,并且也会阻止运行其他查询(不存在引用完整性问题)。我怀疑问题的原因是由于(如您所见)SELECT游标内的语句使用WITH (NOLOCK)脏获取提示。WITH (NOLOCK)然后删除游标内的select语句和with语句中已经使用的表中的数据。WITH (NOLOCK)因为一旦我注释了游标中 select 语句中使用的删除语句,存储过程就可以正常运行。

有人可以解释一下:

  1. 我怀疑的是正确的吗?
  2. 问题的原因是由于WITH (NOLOCK)在游标内的语句中使用并锁定了 DELETE 的记录(在事务内运行)
  3. 我怎样才能防止这个问题?WITH (NOLOCK)从选择语句中删除?

Iva*_*tin 5

删除绝对不必要的游标,删除无意义的NOLOCK。

DECLARE @del TABLE (uniqueId BIGINT NOT NULL PRIMARY KEY)

DELETE em
      OUTPUT DELETED.uniqueId
      INTO @del(uniqueId)
FROM EMPLYEE_MASTER em
WHERE EXISTS(SELECT 1 FROM EMP_DETAILS edt WHERE em.uniqueId = edt.uniqueId)
   AND EXISTS(SELECT 1 FROM EMP_ATTENDANCE ea WHERE em.uniqueId = ea.uniqueId)

DELETE t
FROM EMP_DETAILS t
WHERE EXISTS(SELECT 1 FROM @del d WHERE d.uniqueId = t.uniqueId)
Run Code Online (Sandbox Code Playgroud)

等等

关于光标的旁注

DECLARE TestCursor CURSOR STATIC FOR 
SELECT DISTINCT em.uniqueId 
FROM EMPLYEE_MASTER em
INNER JOIN EMP_DETAILS edt ON em.uniqueId = edt.uniqueId
INNER JOIN EMP_ATTENDANCE ea ON em.uniqueId = ea.uniqueId
Run Code Online (Sandbox Code Playgroud)

DISTINCT- 您正在加入 DETAILS,因此行数将乘以详细信息数,这意味着您将尝试多次删除相同的 uniqueId

STATIC- 您可以这样做,而不是无锁定:使用此选项,服务器将创建临时表并在其中存储选定的值。