SQLSERVER死鎖詳解


看了網上很多關於死鎖的的博客,大家通常介紹死鎖的原理,本人也寫一個詳細的分析。當然,是關於SQLSERVER的死鎖。

使用SQL Profiler抓取死鎖事件

2、選擇選項卡:事件選擇,勾選右下角的顯示所有事件,找到Locks事件,勾選上Deadlock graph。

3、再選擇第三個選項卡:事件提取設置,勾上死鎖XML,彈出文件保存路徑,輸入文件名即可。

4、以上設置,出現死鎖時會保存到死鎖XML文件中,經操作發現只保存了最后一個死鎖圖,如果死鎖比較多,需要使用SQL Profiler逐個保存。

5、死鎖XML文件默認后綴為.xdl,雙擊直接打開就會使用SSMS打開,僅僅只能看到很基礎的信息。如下:

這種圖示並不能詳細的說明問題。我們可以采取另外一種辦法,左鍵選擇死鎖XML文件,右鍵選擇打開方式:文本編輯器。整個死鎖的內容就一目了然了,如下:

 

紅色的框框,是我標注出來的,我主要對黑色框框里面的做詳細說明,其實有很多了解死鎖的朋友看了之后基本已經明白了。

1、  每一個死鎖XML文件有一個根節點:deadlock-list。

2、  在根節點下,有一個節點deadlock victim="process59bcbc8",其中victim值為死鎖的編號,如果打開的一個SQL Profiler下出現多個死鎖,那么它們的編號是一致的,只有不同的SQL Profiler追蹤的死鎖編號才會有不同。此外該值為犧牲的進程ID號,與別的ID號區分,這個在之后會詳細介紹。

3、  在deadlock victim節點下有兩個節點,process-list,resource-list。process-list節點主要解釋死鎖的一些相關信息。resource-list節點解釋鎖的授予情況。

4、  process-list節點,一般有兩個process節點,每個節點代表着一個死鎖中的一個進程,如果多個進程造成的死鎖,那就會出現多個process節點。我們先看第一個process節點,這個節點根據之前的圖片可以看出,是被犧牲的進程。

1)屬性id="process7a9a988",這個是被犧牲的進程ID號,在文件中我們可以看到兩個process節點的ID號不同。另一個節點的id屬性為id="process7abee08"

2) 屬性waitresource=”PAGE: 7:1:8459005”,Page代表這是一個頁鎖,這個頁面出現在數據庫ID=7,文件ID=1,頁面ID=8459005的位置。另一個Procee節點下的waitresource="PAGE: 7:1:7861369"。

3) 屬性transactionname ="SELECT",表示事務類型,SELECT表示這是一個查詢事務,可以跟另一個Procee節點下的transactionname屬性進行比較,transactionname="UPDATE"

4) 屬性lockMode="S",鎖的模式為共享鎖。另一個process節點的鎖模式lockMode="IX"為意向排他鎖。

5) 屬性status="suspended",鎖的狀態。另一個process節點的status="suspended"。

6) 屬性hostname="999VISTA"指操作這個事務的電腦名。另一個process節點的hostname="jack"

7) 屬性loginname="sa"指登錄數據庫的SQL賬戶。另一個process節點的loginname="aaa"。

8) 屬性isolationlevel="read committed (2)"指事務隔離級別。

9) 節點executionStack,在它之下有兩個frame節點,第一個節點中間的文本是執行語句。第二個節點,沒弄明白什么意思。

10) 節點inputbuf,這個節點中間的文本也是執行語句,與executionStack節點下第一個frame節點的文本相同,推測executionStack節點下第二個節點是不是在一個執行進程中其他的SQL語句??

5、  resource-list節點。這個節點下有兩個pagelock節點,分別代表兩個進程各自持有的頁鎖。如果有多個頁鎖,是不是會有多個pagelock節點?或者是表鎖那會是什么節點??

1)  第一個pagelock節點,fileid="1" pageid="8459005" dbid="7",這個跟process-list節點下第一個process節點的屬性waitresource=”PAGE: 7:1:8459005”意思相同。objectname=” 表名",這個是表名,具體格式:db_name.schema_name.Table_name。

2)  pagelock節點下有多個owner-list節點,這個是每一個進程就有一個節點,該示例中由於死鎖是由兩個進程造成,只有兩個節點。

3)  owner-list節點有一個owner,這個代表着鎖的授予情況,推測:如果持有多個鎖,可能有多個節點。

4)  owner節點:id="process7abee08" mode="IX",id表示進程ID,mode表示鎖類型。

5)  pagelock節點下有多個waiter-list節點,這個節點是與owner-list節點一一對應。

6)  waiter-list節點有一個waiter節點,這個代表着鎖的授予情況,推測:如果持有多個鎖,可能有多個節點。

7)  waiter節點:id="process7a9a988" mode="S" requestType="wait",id表示進程ID,mode表示鎖類型,requestType表示等待授予中。

8)  通過以上的介紹,我們可以了解到:

進程process7a9a988先擁有了Page:7:1:7861369的共享鎖S,這個時候,它請求獲取Page:7:1:8459005的共享鎖S,與此同時,process7abee08先擁有了Page:7:1:8459005的意向排他鎖IX,又請求獲取Page:7:1:7861369的意向排他鎖,這樣,兩個進程相互阻塞造成了死鎖的原因。我對此結合數據庫表結構分析,發現該表的每行字段都有6880個字符,也就是說,一行就占用了一個頁面,同時,進程process7a9a988使用的是LINQ查詢,由於LINQ導致這個查詢居然不走聚集索引,先走AccountID字段的索引然后在嵌套循環主鍵索引CaseID,是死鎖的原因之一。

 

 

以上就是本人對死鎖的見解,如有異議,歡迎提出討論。


免責聲明!

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



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