为什么 SELECT 在死锁图中显示更新锁

Why SELECT shows Update lock in deadlock graph

我有两个 SQL 查询(MSSQL 服务器):

SELECT [Value]
FROM [dbo].[BigTable]
ORDER BY [Id] DESC

UPDATE [dbo].[BigTable]
SET [Value] = [Value]

其中 [Id] - 主聚集键。
当我在循环中无限地 运行 它们时,我陷入了死锁,这很明显。但不明显的是(对我而言):为什么在死锁图上我得到“Owner mode: U” for select statement。
据我所知,select语句只能有共享锁。在这里我没有使用任何提示或额外的事务来进行更新锁定。知道为什么我会在这里看到它吗?

XML 附加死锁

<deadlock-list>
 <deadlock victim="process1c094ee5468">
  <process-list>
   <process id="process1c094ee5468" taskpriority="0" logused="0" waitresource="PAGE: 7:1:1502 " waittime="1289" ownerId="901143" transactionname="SELECT" lasttranstarted="2021-05-05T18:04:54.470" XDES="0x1c094329be8" lockMode="S" schedulerid="6" kpid="22644" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2021-05-05T18:04:54.470" lastbatchcompleted="2021-05-05T18:04:54.453" lastattention="1900-01-01T00:00:00.453" clientapp="Core Microsoft SqlClient Data Provider" hostname="ALEXEY-KLIPILIN" hostpid="3132" loginname="sa" isolationlevel="read committed (2)" xactid="901143" currentdb="7" currentdbname="SampleDb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtend="92" sqlhandle="0x02000000bf49f5138395d042205ae64888add734815151770000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
SELECT * FROM [dbo].[BigTable] ORDER BY Id DESC    </inputbuf>
   </process>
   <process id="process1c096e1d088" taskpriority="0" logused="100" waitresource="PAGE: 7:1:1503 " waittime="1289" ownerId="901139" transactionname="UPDATE" lasttranstarted="2021-05-05T18:04:54.470" XDES="0x1c08bc84428" lockMode="X" schedulerid="4" kpid="9160" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-05-05T18:04:54.470" lastbatchcompleted="2021-05-05T18:04:54.397" lastattention="1900-01-01T00:00:00.397" clientapp="Core Microsoft SqlClient Data Provider" hostname="ALEXEY-KLIPILIN" hostpid="3132" loginname="sa" isolationlevel="read committed (2)" xactid="901139" currentdb="7" currentdbname="SampleDb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtend="88" sqlhandle="0x0200000018eeb102d311fd032bb670822f260841060b64410000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
UPDATE [dbo].[BigTable] SET [Value] = [Value]    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <pagelock fileid="1" pageid="1502" dbid="7" subresource="FULL" objectname="SampleDb.dbo.BigTable" id="lock1c0884bdd00" mode="X" associatedObjectId="72057594043760640">
    <owner-list>
     <owner id="process1c096e1d088" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process1c094ee5468" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <pagelock fileid="1" pageid="1503" dbid="7" subresource="FULL" objectname="SampleDb.dbo.BigTable" id="lock1c0a0a23380" mode="U" associatedObjectId="72057594043760640">
    <owner-list>
     <owner id="process1c094ee5468" mode="S"/>
    </owner-list>
    <waiter-list>
     <waiter id="process1c096e1d088" mode="X" requestType="convert"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>

这看起来像是图形表示中的一些错误陈述。

process1c096e1d088(UPDATE)在页面 1502 上持有一个页面级 X 锁,在 1503 上持有一个页面级 U 锁,并且正在尝试转换 U锁到 X 锁。 (requestType="convert")

process1c094ee5468 (SELECT) 在 1503 上持有页级 S 锁(与 U 锁兼容)并正在等待页级 S 锁在 1502.

因为页面锁 1503SU 模式下都持有,所以它在死锁 XML 和 [=35] 中有 mode="U" =] 假定它在该模式下被拦截器持有。

当然,如果 SELECT 事务是在请求 1502 上的锁之前释放其在 1503 上的锁,则不会出现此死锁,但我认为它有充分的理由不这样做(也许是为了停止1502 正在扫描中途解除分配并使其无法访问下一页)。