SQL Server死鎖


SQL Server死鎖

  • 多個事務之間互相等待對方的資源,導致這些事務永久等待
  • 注意是永久等待,而非長事務

死鎖的4個條件

  • 互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。
  • 請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。
  • 非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
  • 循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正占用的資源。

事務隔離級別

  • READ UNCOMMITTED(SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED)
  • READ COMMITTED(SET TRANSACTION ISOLATION LEVEL READ COMMITTED)
  • REPEATABLE READ(SET TRANSACTION ISOLATION LEVEL REPEATABLE READ)
  • SERIALIZABLE(SET TRANSACTION ISOLATION LEVEL SERIALIZABLE)
  • SNAPSHOT(SET TRANSACTION ISOLATION LEVEL SNAPSHOT)

驗證

  • 初始數據
  • 默認隔離等級下,更新事務對事務外SELECT語句的影響
    • 在sql server ssms中分別打開兩個連接,分別模擬事務以及普通SELECT
    • 下面這個事務只有begin,沒有COMMIT或者ROLLBACK,目的是模擬並發時多個session同時運行效果
    • 執行上面這個事務
    • 接着在另外一個session中分別查詢下面這些select
    • /*example 1*/
      SELECT * FROM [dbo].[customer]
      SELECT * FROM [dbo].[customer] WHERE id=1
      SELECT * FROM [dbo].[customer] WHERE id=2
      SELECT * FROM [dbo].[customer](NOLOCK) WHERE id=2
      
    • 分別執行后的結果(結果里空白的為阻塞狀態)

    • 然后在事務session中執行rollback命令
    • 在普通SELECT session中運行下面語句
    • SELECT * FROM [dbo].[customer]
    • 可以看到,這里又變成了aaa(在NOLOCK查詢時這個值為Changed)
    • 結論
      • 在默認隔離級別下(READ COMMITTED),對於UPDATE過的記錄,在事務范圍外默認會被阻塞住
        • 同樣適用於REPEATABLE READ以及SERIALIZABLE,但不適用於READ UNCOMMITTED
        • 同樣適用於DELETE/INSERT記錄
      • 如果在事務外部進行查詢的查詢條件不牽涉到事務內的更新記錄,則外部查詢不會被阻塞
        • 比如WHERE id=2會被阻塞
        • 比如WHERE id=3不會被阻塞
        • 比如WHERE id between 1 AND 3會被阻塞
      • 其他線下證明
        • 例子中是用了pkid來做where條件,但是用其他條件也同樣適用
        • 例子中的pkid有index,但是沒有index的字段同樣也適用
  • SERIALIZABLE隔離等級下,對事務外的SELECT/UPDATE/DELETE影響
    • 初始數據為
    • 執行上面這個更改為serializable的事務
    • 然后在這個事務外部執行下面測試
    • 結論
      • 如果某事務是用了serializable隔離級別,則外部就無法insert任何記錄到相應的表中
        • 無論insert的字段值是否落在where條件內或者外
      • 外部的UPDATE行為:同普通等級
        • 實際上DELETE行為也是
  • 默認隔離級別中插入的記錄,對於外部查詢的影響
    • 執行下面這些測試
    • 結論
      • 如果某事務是用了read committed隔離級別,則外部默認無法看到這些新增的記錄
        • 同樣適用於repeatable read以及serilizable隔離級別
      • 使用了NOLOCK關鍵字的查詢語句能看到臟數據
  • 默認隔離級別下事務死鎖例子
    • 初始數據
    • 我們在2個session中同時執行2個事務,如下
    • 結論
      • 互相等待資源的釋放、同時又持有現有資源,就會造成死鎖
      • 上面例子中被kill掉的事務,選擇犧牲事務的算法,ms稱:正常情況下,SQL Server會把它認為取消或回滾代價最小的連接作為默認的死鎖犧牲品
        • 算了,不深入了
        • 知道還有個非正常情況 - 死鎖優先級,后續
  • 事務優先級 - SET DEADLOCK_PRIORITY(http://msdn.microsoft.com/en-us/library/ms186736.aspx
    • 也可以如下
    • 結論
      • SET DEADLOCK_PRIORITY可以放在SESSION的任何地方,無論是事務外還是內、前還是后
        • sqlserver探測到死鎖后,會根據session的deadlock優先級來kill
      • LOW/NORMAL/HIGH
        • 分別代表
          • -5/0/5
      • 也可以使用數字
        • -10直到10

避免死鎖的建議

  • 把SELECT放在事務范圍外
  • 將多個事務合並為一個事務
  • SELECT加With(NOLOCK)提示
  • 降低事務隔離級別, 比如READ UNCOMMITTED
  • 使用基於行版本控制的隔離級別

 

 

 


免責聲明!

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



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