SQL Server 死鎖概念和分析


鎖的概念

  • 鎖是什么

鎖是數據庫中在並發操作情形下保護資源的機制。通常(具體要看鎖兼容性)只有鎖的擁有者才能對被鎖的資源進行操作,從而保證數據一致性。

  • 鎖的概念可分為幾部分
  1. 鎖資源(鎖住什么)
  2. 鎖模式(怎么鎖法)
  3. 鎖持續時間
  4. 兼容性
  5. 鎖的行為(鎖轉換,鎖升級)

 

1.鎖的資源


 

2.鎖的模式

  1. 共享鎖:Shared Lock,S Lock. 通常情況下,讀取數據時會對數據加上S Lock。
  2. 排它鎖: Exclusive Lock,X Lock。對數據進行更改(insert update,delete)時加X Lock
  3. 更新鎖:Update Lock,U Lock(或叫UPD Lock)。通常對數據進行Update操作會加U鎖。查找數據時會加U鎖,找到后對數據進行更改時在轉換為X鎖。U鎖是為了防止在並發對數據進行更新時出現死鎖,因為如果先加S鎖再轉換為X鎖,由於S鎖和S鎖兼容,但X鎖和S鎖不兼容,所以有可能出現死鎖。
  4. 意向鎖:Intent Lock(例如:IX,IU,IS),是指對被鎖定的資源的上層資源加鎖。意向鎖是為了提高鎖的效率。例如對行加X鎖,會對表加IX鎖(意向排他鎖),如果其他線程或事物想對該表加X鎖,就不用逐行檢查是否有其他所,只需檢查是否有IX鎖(或其他意向鎖)

3.鎖在事務中的持續時間

不同的事務隔離級別下,鎖有不同的持續時間。 (單一個SQL語句也是一個事物,稱為“自動提交事務”,用begin tran/commit聲明的是顯式事務)

  1. Read uncommitted: select不會加鎖(no lock),但更新會加U鎖並持續到事務介紹
  2. Read committed:select加S鎖,讀完釋放。U鎖和X鎖持續到事務結束
  3. Repeatable Read : select加S鎖,但讀完不釋放,和U鎖,X鎖一樣持續到事務結束。
  4. Serializable :select會加范圍鎖,讀完不釋放,和U鎖,X鎖一樣持續到事務結束。

 

4.鎖兼容性

鎖兼容性是指不同模式的鎖能不能共存。鎖兼容性對照圖:

圖片出自Microsoft

 

5.鎖轉換和鎖升級

  1. 鎖轉換:鎖會由一種模式轉換為另一種模式。例如delete一條數據,先在數據查找時對數據加上U鎖,再在准備刪除數據前轉換成X鎖。
  2. 鎖升級:為了提高效率,鎖會從一種粒度升級到另一種粒度。一個鎖大概需要96B空間,如果鎖太多會占用太多資源。如果一個操作需要對很多資源加鎖,SQL會自動對這個資源的上級加相同的鎖,即鎖升級

 

死鎖的概念

死鎖就是兩個或多個會話(SPID)相互請求對方持有的鎖資源,導致循環等待的情況。

 

死鎖的檢查和分析

在Profiler中使用Deadlock Graph分析死鎖

 

 

捕獲到死鎖圖

 

也可以使用ErrorLog來記錄死鎖

  • 打開trace flag
    • dbcc traceon(1204,-1)
    • dbcc traceon(1222,-1)
  • 清空errorLog(不一定需要清空,只為減少log數據)
    • dbcc errorlog或者  exec sp_cycle_errorlog
  • 打開errorlog文件或者執行 xp_readerrorlog
  • 分析死鎖圖,如下圖:

 

 

根據errorlog內容畫出死鎖圖,其中:

  • NODE:代表每個死鎖節點
  • Key/RID/Object:被鎖定的資源
  • Grant List:擁有該資源的鎖的SPID
  • Reuested List:請求該資源的SPID
  • SPID:會話ID
  • MODE: 該資源被鎖定的模式。參考:鎖模式
  • Input Buf:發生死鎖時的SQL語句

這樣就可以畫出死鎖圖:

這樣便可以分析出死鎖的情況,當然如果對errorlog已經比較熟悉,就可以不用畫出死鎖圖了。

 

死鎖和索引

  • 如果被鎖的資源是一個Object,只有object_id,可以通過Object_name()函數獲取object的名字。
  • 如果是RID,可以通過 dbcc page指令去知道哪行數據被鎖。
  • 如果是key,需要通過 %%lockres%%列,或者“dbcc ind指”令和“dbcc page”指令去知道哪個索引鍵被鎖。
  • 在死鎖節點的Key中,顯示被鎖的key為:

 KEY: 49:72057594189512704 (11036c0fa4d3),格式為:
 KEY: db_id:hobt_id(index key hash value)
SQL SERVER通過對一個由索引鍵值生成的hash value進行鎖定,來達到對索引鎖定的目的。其中(11036c0fa4d3)就是某個key的hash value。
如何由hash value得知是哪行數據被鎖定? 請按以下步驟:

如果是聚集索引,可以使用%%lockres%%隱藏列獲取lock hash value:

 

如果是非聚集索引,%%lockres%%只顯示 RID。如果需要確定數據行對應的索引頁中的索引鍵,需要使用dbcc ind和dbcc page指令進行分析:

  • 要查看索引的lock hash value,需要查看索引所在的數據頁的內容。
  • 要知道索引在什么數據頁中,需要使用dbcc ind指令: dbcc ind(‘moe_dev’,592773219,3)  “592773219”代表表的object_id,3代表索引的index_id 。可使用dbcc ind指令:

 

知道了索引所在數據頁的Page_ID,可以使用dbcc page指令查看數據頁內容(最后一個參數必須為“3”):

 

知道了索引所在數據頁的Page_ID,可以使用dbcc page指令查看數據頁內容(最后一個參數必須為“3”):

 

知道了key hash value和Heap RID,可以通過下面的SQL語句轉換成RID

DECLARE @HeapRid BINARY(8)
SET @HeapRid = 0xDB27000001001700
SELECT 
       CONVERT (VARCHAR(5),
                    CONVERT(INT, SUBSTRING(@HeapRid, 6, 1)
                               + SUBSTRING(@HeapRid, 5, 1)))
     + ':'
     + CONVERT(VARCHAR(10),
                    CONVERT(INT, SUBSTRING(@HeapRid, 4, 1)
                               + SUBSTRING(@HeapRid, 3, 1)
                               + SUBSTRING(@HeapRid, 2, 1)
                               + SUBSTRING(@HeapRid, 1, 1)))
     + ':'
          + CONVERT(VARCHAR(5),
                    CONVERT(INT, SUBSTRING(@HeapRid, 8, 1)
                               + SUBSTRING(@HeapRid, 7, 1)))
                               AS 'Fileid:Pageid:slot'

得到的RID為:

通過dbcc page指令就可以查看是哪行被鎖定了。

 

參考資料

有關死鎖的資料和比較好的文章,請看另一篇博文《有關DeadLock的文章列表


免責聲明!

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



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