sql server死鎖:identify導致的 insert 和 select max(id)


【1】死鎖信息

【1.1】圖

  

左邊:select max(id) from tab 
右邊:insert into tab values.....

兩個語句是同一個表,id是主鍵、聚集索引

【1.2】XML

Deadlock graph    <deadlock-list>
 <deadlock victim="process9ada68">
  <process-list>
   <process id="process9ada68" taskpriority="0" logused="0" waitresource="PAGE: 102:1:5940067" waittime="3953" ownerId="1571798125" transactionname="user_transaction" lasttranstarted="2020-11-16T12:04:38.950" XDES="0x55282258" lockMode="S" schedulerid="2" kpid="2896" status="suspended" spid="80" sbid="1" ecid="0" priority="0" transcount="1" lastbatchstarted="2020-11-16T12:04:38.950" lastbatchcompleted="2020-11-16T12:04:38.950" clientapp="Microsoft SQL Server" hostname="iZqcugpmvybrkfZ" hostpid="1596" loginname="sa" isolationlevel="read committed (2)" xactid="1571798125" currentdb="102" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000002b707300c7eefdadd6f8dfe7f8457b5eb4e02c32">
SELECT MAX(&quot;Tbl1002&quot;.&quot;ID&quot;) &quot;Expr1003&quot; FROM &quot;QPRecordDB&quot;.&quot;dbo&quot;.&quot;RecordUserInout&quot; &quot;Tbl1002&quot;     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 32767 Object Id = 315066412]    </inputbuf>
   </process>
   <process id="processfe03e8" taskpriority="0" logused="620" waitresource="PAGE: 102:1:5940068" waittime="3953" ownerId="1571798118" transactionname="user_transaction" lasttranstarted="2020-11-16T12:04:38.950" XDES="0x37f294a8" lockMode="IX" schedulerid="3" kpid="4960" status="suspended" spid="83" sbid="1" ecid="0" priority="0" transcount="2" lastbatchstarted="2020-11-16T12:04:38.950" lastbatchcompleted="2020-11-16T12:04:38.950" clientapp="Microsoft SQL Server" hostname="iZqcugpmvybrkfZ" hostpid="1596" loginname="sa" isolationlevel="read committed (2)" xactid="1571798118" currentdb="102" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="316" sqlhandle="0x020000002109bb37cd7e5870d56e6418e1fe6003a303a1c9">
INSERT [QPRecordDB].[dbo].[RecordUserInout]([UserID],[KindID],[ServerID],[EnterScore],[EnterUserMedal],[EnterLoveliness],[EnterMachine],[EnterClientIP]) VALUES(@Param000004,@Param000005,@Param000006,@Param000007,@Param000008,@Param000009,@Param000010,@Param000011)     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@Param000004 int,@Param000005 int,@Param000006 int,@Param000007 bigint,@Param000008 int,@Param000009 int,@Param000010 nvarchar(33),@Param000011 nvarchar(15))INSERT [QPRecordDB].[dbo].[RecordUserInout]([UserID],[KindID],[ServerID],[EnterScore],[EnterUserMedal],[EnterLoveliness],[EnterMachine],[EnterClientIP]) VALUES(@Param000004,@Param000005,@Param000006,@Param000007,@Param000008,@Param000009,@Param000010,@Param000011)    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <pagelock fileid="1" pageid="5940067" dbid="102" objectname="QPRecordDB.dbo.RecordUserInout" id="lockffffffff80008e00" mode="IX" associatedObjectId="72057594056540160">
    <owner-list>
     <owner id="processfe03e8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9ada68" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <pagelock fileid="1" pageid="5940068" dbid="102" objectname="QPRecordDB.dbo.RecordUserInout" id="lockffffffffb86aa940" mode="S" associatedObjectId="72057594056540160">
    <owner-list>
     <owner id="process9ada68" mode="S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processfe03e8" mode="IX" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>
    

【2】分析思路

【2.1】語句分析

select max(id) from RecordUserInout

 

 

(1) 當我用max(id)查詢的時候,它會順着索引去找最大的,比如找到了最大記錄在這個頁,它會這個頁上加上S鎖

(2) 接着insert into values插入的時候,它需要同時在這兩個頁上寫數據,於是向這個頁上加IX鎖

(3) 但是第一個頁已經加了S鎖,於是第一個頁的IX就會等待,但是第二個頁就不需要

怎么想都感覺不是很對

難道是這樣?

(1)select max(id) 要掃描整個聚集索引樹才能找到max(id),對聚集索引樹頁都加了S鎖
(2)同時,在select max(id) 還沒找到的時候,insert into 插入到了最后面,然后它排它X了, 然后它需要X鎖來更新聚集索引上層頁
(3)但這個時候上層頁正在被select 給S鎖阻塞住了
(4)select max(id) 的后續掃描又被 insert 的X鎖給阻塞了

感覺其實也不是很對,既然

【2.2】思路分析

可能是跟蹤只是捕獲到當前語句,但沒有語句所在事務的相關上下文,找程序看一看

【3】解決思路

對select max(id)  from tab 做  with(nolock)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM