天天看點

SQL Server 死鎖案例分析概述死鎖發生原理案例分析死鎖調優建議

當兩個或者多個程序互相阻塞時,形成一個複雜的阻塞鍊,參與的程序都在等待其他程序放棄其擷取到的鎖,沒有系統的幹預,無法解開這個阻塞鍊,這種情況就是死鎖。

有些死鎖是意料之内的,可以說是故意為之的。 例如,為了一緻性,使用死鎖來防止丢失更新。 有一些死鎖是意料之外的,由于缺少索引或者事務運作時間較長導緻,我們遇到的大部分都是意料之外的死鎖。 

sql server内部有個死鎖的檢測機制,當發生死鎖時,sql

server根據會話優先級以及工作量進行評估, 選擇終止其中一個事務,解開死鎖,并且向發起該事務的用戶端發送下面的錯誤資訊。

error message:

msg 1205, level 13, state 47, line 1transaction

(process id 53) was deadlocked on lock resources with another process and has

been chosen as the deadlock victim. rerun the transaction.

死鎖其實本質上是兩個或者多個session互相阻塞。 阻塞的發生,實際上是不同的連接配接申請的鎖互相不相容而産生的。例如,當一個連接配接持有x鎖時,另外一個連接配接想要來申請同一資源上面的其他任意的鎖,都會被阻塞。sql server中鎖的相容性表如下。

SQL Server 死鎖案例分析概述死鎖發生原理案例分析死鎖調優建議

如果是ecs上自建的sql server執行個體,那麼很幸運,有種便捷的方法,可以開啟trace flag 1222,将死鎖實時記錄在錯誤日志中。

一般來說,sql server profiler和1222記錄下來的死鎖日志是比較全面的。sql server profiler收集死鎖日志,消耗性能較高,但是自動顯示出死鎖圖譜,便于分析。

SQL Server 死鎖案例分析概述死鎖發生原理案例分析死鎖調優建議

對于1222在錯誤日志中收集死鎖資訊,可以一直開啟,隻會在發生死鎖是記錄在日志中,對性能影響較小,不過分析稍微複雜些。錯誤日志的分析過程如下:

死鎖發生的主要時間段是6月3号10:00至11:38, 10:00:06.16發生的死鎖的程序,鎖和資源資訊如下:

SQL Server 死鎖案例分析概述死鎖發生原理案例分析死鎖調優建議

程序process89a9a6748 在資源pageid=227126上面持有ix鎖,此時process43c824748想要申請該page上的u鎖,被阻塞。 同時process43c824748持有pageid=11768上持有u鎖,此時process89a9a6748需要申請該頁上的u鎖,被阻塞。此時,兩個程序互相阻塞,形成死鎖。

死鎖資源

資源1

資源2

資源類型

pagelock

具體内容

pageid=11768 dbid=37

pageid=227126 dbid=37

持有資源程序

process43c824748

process89a9a6748

等待資源程序

程序process89a9a6748執行語句

程序process43c824748執行語句

上述的死鎖問題,根據觀察表結構和語句執行計劃等資訊,建議在表wf.completedtask的taskid字段上面加一個非聚集索引,提升update執行速度,減少u鎖的持有時間。

由于形成死鎖的原因有很多,例如事務運作時間長,導緻鎖持有時間長或者應用通路資源的順序混亂,造成頻繁鎖沖突等。針對常見的死鎖情況,建議按照下面的幾點進行調優。

1. 檢視是否有長時間未送出的事務,及時送出事務。

2. 是否缺少合适索引,導緻語句運作較慢。

3. 檢查應用程式邏輯,按順序通路某個資源。

4. 對于s鎖參與的情況,使用with(nolock)查詢hint,避免申請s鎖。例如 select * from table with(nolock)。