SQLServer中的死鎖的介紹


簡介

     什么是死鎖?

     我認為,死鎖是由於兩個對象在擁有一份資源的情況下申請另一份資源,而另一份資源恰好又是這兩對象正持有的,導致兩對象無法完成操作,且所持資源無法釋放。

      什么又是阻塞?

     阻塞是由於資源不足引起的排隊等待現象。比如同時兩個進程去更新一個表。

     這里我們可以把阻塞作為死鎖的必要條件。下面我們先理解一下死鎖和阻塞再來看一下我最近遇到一個問題以及解決思路。

SQLServer中的死鎖

     對應到SQL Server中,當在兩個或多個任務中,如果每個任務鎖定了其他任務試圖鎖定的資源,此時會造成這些任務永久阻塞,從而出現死鎖;

   這些資源可能是:單行(RID,堆中的單行)、索引中的鍵(KEY,行鎖)、頁(PAG8KB)、區結構(EXT,連續的8)、堆或B(HOBT) 、表(TAB,包括數據和索引)、文件(File,數據庫文件)、應用程序專用資源(APP)、元數據(METADATA)、分配單元(Allocation_Unit)、整個數據庫(DB)

    下面我簡單舉一個例子來說明一下死鎖的原理:

    

 

 如圖,按步驟執行:

1. begin tran
update test1 set aaa=1

2.

begin tran

update test2 set aaa=1

update test1 set bbb=2

3.再次執行圖1中的Update test2 set bbb=2

執行完成后發現數據並未插入,且一直處於running狀態

 

這個時候我們通過語句查詢死鎖的進程和語句。得到如下結果:

 

很容易發現發生死鎖的語句,也可以使用 SQL Server Profiler 分析死鎖: Deadlock graph 事件類添加到跟蹤。此事件類使用死鎖涉及到的進程和對象的 XML 數據填充跟蹤中的 TextData 數據列。SQL Server 事件探查器 可以將 XML 文檔提取到死鎖 XML  文件中,以后可在 SQL Server Management Studio 中查看該文件。如圖:

接下來我們說一下如何處理死鎖

      1.臨時解決方案,先Kill 掉死鎖的進程,只是暫時解決這個問題。

      2.SQL Server自動選擇一條SQL作死鎖犧牲品:當死鎖發生時,鎖監視器線程執行死鎖檢查,數據庫引擎 選擇運行回滾開銷最小的事務的會話作為死鎖犧牲品,返回1205 錯誤,回滾死鎖犧牲品的事務並釋放該事務持有的所有鎖,使其他線程的事務可以請求資源並繼續運行。

服務器: 消息 1205,級別 13,狀態 50,行 1 事務(進程 ID  xx)與另一個進程已被死鎖在  lock 資源上,且該事務已被選作死鎖犧牲品。請重新運行該事務。

     3.使用SET LOCK_TIMEOUT timeout_period(單位為毫秒)來設定請求超時。 

     4.在SQLServer 和程序兩個方面都可以做代碼上修正,這里不在詳細描述,主要是通過發現死鎖等待一段時間后再次嘗試的方式來解決。

預防和避免死鎖

     1.盡量減少事務執行的時間。

     2.在合理的范圍內降低隔離級別。

     3.同一個事務內盡量避免出現循環對同一個表的處理。

     4.同一個事務內較少用戶交互,即鎖的競爭。

     5.盡量保證邏輯處理的順序比如對表的處理都按照一個順序進行。

     6.對於需要各種邏輯處理的表,可以通過增加索引的方式來減少鎖的競爭。

     7.盡量減少非聚集索引的include 的列,也能減少外鍵死鎖的發生。

     8.同一個對象盡量采用select 在update 前來使用。

     9.對於實時性要求不高的可以使用with(nolock)來實現對表的查詢,但是可能會差生臟讀。

 

 總結

      本文簡單的介紹了死鎖的原因,如何解決和預防。當然任何事情都是雙刃劍,還要我們根據實際情況來合理減少死鎖和阻塞的發生;對於不同隔離界別鎖帶來的問題可以看一下我之前的一篇關於鎖的介紹。希望對死鎖發生預防和解決有一定的幫助。


免責聲明!

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



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