[翻譯]:SQL死鎖-為什么會出現死鎖


下面這篇對理解死鎖非常重要,首先死鎖是如何產生的我們要清楚。

We already know why blocking occurs in the system and how to detect and troubleshoot the blocking issues. Today I’d like us to focus on the deadlocks.First, what is the deadlock? Classic deadlock occurs when 2 processes compete for the resources and waiting on each other. Let’s take a look on that. Click on each picture below to open them in the different window. Let’s assume that Orders table has the clustered index on ID column.Let we have the session 1 that starts transaction and updates the row from the Order table. We already know that Session 1 acquires X lock on this row (ID=1) and hold it till end of transaction

我們已經知道為什么系統中會出現阻塞,也知道如何去探測這些引起阻塞的本質原因。今天我們將重點關注在死鎖上。首先,什么是死鎖呢?最經典的死鎖出現在兩個線程為了搶奪同一資源而相互競爭以至於出現你依賴我你依賴我的死循環情況。請看下圖的圖,我們假定在訂單表Id列上有一個聚集索引,會話1開起一個事務去更新訂單表的數據。此時會話1會在行數據(ID=1)上申請排它鎖至於更新的事務結束。

Now let’s start session 2 and have it update another row in the Orders table. Same situation – session acquires and holds X lock on the row with (ID = 2).

現在,我們開啟會話2也更新訂單表,不同的是更新的數據行為Id=2,同樣的在數據行Id=2上也會申請排它鎖至到更新事務的結束。

Now if session 1 tries to acquire X lock on the row with ID = 2 , it cannot do that because Session 2 already held X lock there. So, Session 1 is going to be blocked till Session 2 rollback or commit the transaction

現在,如果會話1嘗試在數據行Id=2上申請排它鎖,將會受到阻塞,因為會話2已經申請了排它鎖。只有當會話2回滾或者提交事務后才能夠重新嘗試獲取排它鎖。

It worth to mention that it would happen in any transaction isolation level except SNAPSHOT that handles such conditions differently. So read uncommitted does not help with the deadlocks at all.

這里值得提醒的時,上面的場景需要排除鏡像這種特殊優化過的隔離模式。所以從上面的例子來看,read uncommitted隔離模式是不能幫忙我們解決死鎖問題的。

Simple enough. Unfortunately it rarely happens in the real life. Let’s see it in the small example using the same dbo.Data table like before. Let’s start 2 sessions and update 2 separate rows in the table (acquire X locks).

 

足夠簡單,但上面的場景並不常出現。下面我們采用之前使用數據表,我們打開兩個會話去更新不同的數據行。

 

Session 1:

會話1,更新ID=0的數據行

Session 2:

會話2,更新ID為40000的數據行

Now let’s run 2 selects.

現在我們再運行兩個查詢語句

Session 1:

會話1,查詢Value=1的數據

Session 2:

會話2,查詢Value=40001的數據

Well, as you can see, it introduces deadlock.

如下圖所示,我們看到了死鎖的相關提示

To understand why it happens, let’s take a look at the execution plan of the select statement:

為了理解到底發生了什么,我們看一相查詢所產生的實際執行計划

As you can see – there is the table scan. So let’s think what happened

如上圖所示,這是一個表掃描,我們來想一下發生了什么:

  1. First of all, we have 2 X locks on the different rows acquired by both sessions.

          首先,我們有兩個排它鎖在不同的數據行上,每個會話占用一個。

  1. When session 1 ran select, it introduced table scan. In read committed, repeatable read or serializable isolation levels, readers issue shared S locks, so when session 1 tried to read the row with ID = 40000 (X lock held by session 2) – it was blocked.

          當會話1執行查詢時,它會引發表掃描,在三種悲觀事務隔離級別事務中(除read uncommitted),讀會產生共享鎖,所有當會話1嘗試去讀取Id=40000的數據行時就會出現阻塞,因為會話2更新數據行的事務並未結束。

  1. Same thing happens with session 2 – it’s blocked on the row with ID = 1 (X lock held by session 1).

          同樣的情況出現在會話2中,當它嘗試去讀取ID=1的數據行時,此時由於會話1更新的事務並未結束,所以此次查詢也會被阻塞。

So this is the classic deadlock even if there are no data updates involved. It worth to mention that read uncommitted transaction isolation level would not introduce deadlock – readers in this isolation level do not acquire S locks. Although you’ll have deadlock in the case if you change select to update even in read uncommitted level. Otimistic isolation levels also behave differently and we will talk about it later.So as you can see, in the real life as other blocking issues deadlocks happen due non-optimized queries.

這是經典的死鎖場景即使此時沒有任何相關的數據被更新。這里值得再次提醒的是,在read uncommitted事務隔離級別下是不能減少死鎖的,盡管在此模式時並不需要申請共享鎖。

        注:本篇文章中一直來講read uncommitted模式不能解決死鎖,在本篇沒有舉例子,但之前的系列文章中已經有了,可以詳細參考。

Next week we will talk how to detect and deal with deadlocks.

下一次我將講如何探測死鎖以及如何處理死鎖問題。


免責聲明!

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



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