Sql server SQL Server中一个非常奇怪的密钥锁死锁

Sql server SQL Server中一个非常奇怪的密钥锁死锁,sql-server,Sql Server,非常奇怪的是,当有两个连接在不同的行上运行下面的事务时,会检测到死锁。为什么查询优化器要求事务T1具有由事务T2更新的行资源键2 键1(第1行)键:5:72057594048348160(150fa2746afc) 键2(第2行)键:5:72057594048348160(1BEC17E39AE) 2个事务同时更新不同的行。假设它们没有使用UPLOCK和ROWLOCK相互干扰 BEGIN TRAN SELECT * FROM TABLE WITH(UPLOCK, ROWLOCK) WHERE P

非常奇怪的是,当有两个连接在不同的行上运行下面的事务时,会检测到死锁。为什么查询优化器要求事务T1具有由事务T2更新的行资源键2

键1(第1行)键:5:72057594048348160(150fa2746afc)

键2(第2行)键:5:72057594048348160(1BEC17E39AE)

2个事务同时更新不同的行。假设它们没有使用UPLOCK和ROWLOCK相互干扰

BEGIN TRAN
SELECT * FROM TABLE WITH(UPLOCK, ROWLOCK) WHERE PK_COL1 = ? and PK_COL2 = ?
UPDATE TABLE SET COL3 = ? WHERE PK_COL1 = ? and PK_COL2 = ?
END
下面是死锁列表

<process id="process10e7502c8" taskpriority="0" logused="0" waitresource="KEY: 5:72057594048348160 (150fa2746afc)" 
....
<process id="process10e750988" taskpriority="0" logused="0" waitresource="KEY: 5:72057594048348160 (1bec117e39ae)" 
...
<resource-list>
  <keylock hobtid="72057594048348160" dbid="5" objectname="" indexname="" id="locka6b73300" mode="U" associatedObjectId="72057594048348160">
    <owner-list>
      <owner id="process10e750988" mode="U" />
    </owner-list>
    <waiter-list>
      <waiter id="process10e7502c8" mode="U" requestType="wait" />
    </waiter-list>
  </keylock>
  <keylock hobtid="72057594048348160" dbid="5" objectname="" indexname="" id="locka5319b80" mode="U" associatedObjectId="72057594048348160">
    <owner-list>
      <owner id="process10e7502c8" mode="U" />
    </owner-list>
    <waiter-list>
      <waiter id="process10e750988" mode="U" requestType="wait" />
    </waiter-list>
  </keylock>
</resource-list>
如果我添加一个与主键创建的聚集索引具有相同列和顺序的未聚集索引,死锁问题就会消失。但为什么更新聚集索引键上的行需要更新其他聚集索引键上的锁

如果我有任何误解,请纠正我。如有任何答复,将不胜感激

表模式描述如下SQL脚本所示

create table [dbo].[TABLE1]
(
[PK_COL1] char(10) not null,
[PK_COL2] char(10) not null,
[COL3] char(10) not null,
PRIMARY KEY ([PK_COL1],[PK_COL2])
);

添加
readpass
提示:

BEGIN TRAN
    SELECT * FROM TABLE WITH(UPDLOCK, ROWLOCK, READPAST) 
    WHERE PK_COL1 = ? and PK_COL2 = ?
    UPDATE TABLE SET COL3 = ? WHERE PK_COL1 = ? and PK_COL2 = ?
COMMIT TRAN
正如@CJBS在评论中指出的,提示的使用应限于需要提示的情况,并且您完全理解其后果


上面示例中的提示出现在使用表作为队列的示例中,您希望选择一行,对其进行锁定,并在单独的语句中进行更新(例如在处理后删除该行),但也允许其他读卡器读取超过保留的更新锁的行。

我最终发现,需要非聚集索引来避免死锁

CREATE NONCLUSTERED INDEX [TABLE1_IDX1] ON [TABLE1]([PK_COL1], [PK_COL2]);

相关报道:米奇,答案不起作用。聚集索引是否严重碎片化?不应该。它只有不到100条记录。我试图重建索引,但死锁问题仍然存在。请发布完整的TSQL表架构定义。Hi Mitch。这不是针对你的。相反,它是对任何可能在不理解其含义的情况下使用表提示的人的警告。
CREATE NONCLUSTERED INDEX [TABLE1_IDX1] ON [TABLE1]([PK_COL1], [PK_COL2]);