Sql-Server

什麼會導致此 SQL Server 死鎖?

  • May 24, 2021

我有一個 node.js 腳本試圖對錶中的記錄進行地理編碼。該腳本一次選擇 100 條沒有緯度/日誌數據的記錄,使用第三方 api 對其進行地理編碼,並將結果寫入相應記錄的緯度/經度列。此腳本導致數據庫中出現死鎖錯誤,如下所示:

事務(程序 ID 69)與另一個程序在鎖資源上死鎖,並已被選為死鎖犧牲品。重新執行事務。

我設置 SQL Server Profiler 來執行跟踪和跟踪死鎖數據,並且能夠獲得其中一個死鎖圖,但我無法完全弄清楚為什麼會發生死鎖。這兩個語句都是針對同一個表中的不同記錄的更新。我檢查了隔離級別,它是Read Committed。雖然我沒有處理過很多數據庫死鎖,但我認為這些類型的事務不會導致死鎖。我在下麵包含了 XML,以防萬一:

<deadlock-list>
<deadlock victim="process25211037848">
 <process-list>
  <process id="process25211037848" taskpriority="0" logused="0" waitresource="PAGE: 8:1:34878 " waittime="2422" ownerId="3315762" transactionname="UPDATE" lasttranstarted="2021-05-23T23:46:32.920" XDES="0x24d9e44d900" lockMode="U" schedulerid="4" kpid="7440" status="suspended" spid="65" sbid="0" ecid="4" priority="0" trancount="0" lastbatchstarted="2021-05-23T23:46:32.923" lastbatchcompleted="2021-05-23T23:46:32.380" lastattention="1900-01-01T00:00:00.380" clientapp="Node.js" hostname="PNS157" hostpid="6536" isolationlevel="read committed (2)" xactid="3315762" currentdb="8" currentdbname="DW_Staging" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame procname="adhoc" line="1" stmtstart="100" stmtend="250" sqlhandle="0x02000000259d222f04b5eda0f2e0ab46a16fa9ba5cc2d8310000000000000000000000000000000000000000">
unknown     </frame>
    <frame procname="adhoc" line="1" stmtend="236" sqlhandle="0x02000000a6f84a131709260f562f587021ed884c3ed1e86a0000000000000000000000000000000000000000">
unknown     </frame>
   </executionStack>
   <inputbuf>
UPDATE Members SET MbrLat = 28.03195, MbrLong = -81.09178 WHERE MemberUID = 'ID456'    </inputbuf>
  </process>
  <process id="process24eae1b64e8" taskpriority="0" logused="0" waitresource="PAGE: 8:1:36694 " waittime="2422" ownerId="3315758" transactionname="UPDATE" lasttranstarted="2021-05-23T23:46:32.920" XDES="0x25206e8b900" lockMode="U" schedulerid="3" kpid="7784" status="suspended" spid="79" sbid="0" ecid="2" priority="0" trancount="0" lastbatchstarted="2021-05-23T23:46:32.920" lastbatchcompleted="2021-05-23T23:46:32.480" lastattention="1900-01-01T00:00:00.480" clientapp="Node.js" hostname="PNS157" hostpid="6536" isolationlevel="read committed (2)" xactid="3315758" currentdb="8" currentdbname="DW_Staging" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame procname="adhoc" line="1" stmtstart="100" stmtend="250" sqlhandle="0x02000000d48bf12084e55043f1f9c7969865359e9737b71a0000000000000000000000000000000000000000">
unknown     </frame>
    <frame procname="adhoc" line="1" stmtend="244" sqlhandle="0x02000000424e371e647b248bf01785555348ca7d05f180650000000000000000000000000000000000000000">
unknown     </frame>
   </executionStack>
   <inputbuf>
UPDATE Members SET MbrLat = 25.9510963, MbrLong = -81.1176539 WHERE MemberUID = 'ID123'    </inputbuf>
  </process>
 </process-list>
 <resource-list>
  <pagelock fileid="1" pageid="34878" dbid="8" subresource="FULL" objectname="DW_Staging.dbo.Members" id="lock24ed7f99880" mode="U" associatedObjectId="72057594044678144">
   <owner-list>
    <owner id="process24eae1b64e8" mode="U"/>
   </owner-list>
   <waiter-list>
    <waiter id="process25211037848" mode="U" requestType="wait"/>
   </waiter-list>
  </pagelock>
  <pagelock fileid="1" pageid="36694" dbid="8" subresource="FULL" objectname="DW_Staging.dbo.Members" id="lock24e383d5f00" mode="U" associatedObjectId="72057594044678144">
   <owner-list>
    <owner id="process25211037848" mode="U"/>
   </owner-list>
   <waiter-list>
    <waiter id="process24eae1b64e8" mode="U" requestType="wait"/>
   </waiter-list>
  </pagelock>
 </resource-list>
</deadlock>
</deadlock-list>
   

誰能明白為什麼會發生這種死鎖?關於如何解決這些死鎖錯誤或我應該如何調試問題的任何建議?

更新- 回答以下問題:

  • 我沒有關於 MemberUID 的索引
  • 執行計劃可以在這裡找到。

因為表上沒有合適的索引,所以會進行全表掃描。

表掃描是並行的,這意味著訪問是無序的。你可以通過使用來解決這個問題OPTION(MAXDOP 1),但這只是一個創可貼。

**你最好的辦法是創建一個索引來服務這個查詢,**這個想法是查詢只需要對它需要的確切行進行點查找。

在不知道您有其他疑問的情況下,我只能基於此提出建議

CREATE NONCLUSTERED INDEX IX_Members_MemberUID ON Members (MemberUID) INCLUDE (MbrLat, MbrLong);

鑑於該列被稱為MemberUID它可能是主鍵,在這種情況下,您幾乎可以肯定地將其CLUSTERED設為索引

CREATE UNIQUE CLUSTERED INDEX CX_Members_MemberUID ON Members (MemberUID);

或更好

--  DROP CONSTRAINT the old primary key then ...

ALTER TABLE Members
   ADD CONSTRAINT PRIMARY KEY CLUSTERED (MemberUID);

引用自:https://dba.stackexchange.com/questions/292131