SQL Server 死鎖問題的分析

2021-09-22 02:49:48 字數 4372 閱讀 6387

一、什麼是死鎖?

簡單來說,我和你,金鎖和銀鎖。

我拿著金鎖,我需要再拿到銀鎖,才能完成任務,

你拿著銀鎖,你需要再拿到金鎖,才能完成任務。

我拿不到銀鎖,你拿不到金鎖,這就形成死鎖了。

二、死鎖發生後,sql server怎麼處理?

sql server內建有死鎖偵測和處理機制,每5s會檢測一次,如果有死鎖,就會評估下哪個事務回滾的開銷比較低,將其kill掉,然後反饋1205錯誤。

實際上並沒有這麼簡單,比如可以設定會話的優先順序,優先順序越低,被選為犧牲品的可能性就越大。

三、死鎖發生後怎麼處理?

捕獲死鎖》分析死鎖》解決方案

先模擬獲取死鎖的demo

/*建表*/

create table [dbo].[deadlocktest](

[id] [int] identity(1,1) not null,

[userid] [varchar](10) null,

[num] [int] null,

constraint [pk_deadlocktest] primary key clustered

( [id] asc

)with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]

) on [primary]

/*建索引*/

create index ix_userid on deadlocktest(userid)

/*生成測試資料*/

insert into deadlocktest select 1,1

insert into deadlocktest select 2,2

/*事務1*/ --我

begin tran

update deadlocktest set num=100 where id=1 --金鎖

update deadlocktest set num=100 where id=2 --銀鎖 !!注意這一句執行事務2後,回來再執行

/*事務2*/ --你

begin tran

update deadlocktest set num=100 where id=2 --銀鎖

update deadlocktest set num=100 where id=1 --金鎖

結果:

1、捕獲死鎖,方法較多,常用的兩種方法

>>開啟跟蹤標誌 1222 [rds不支援],可以從sql server日誌中獲取到死鎖資訊

>>sql server profiler抓取

2、分析死鎖

完整的死鎖資訊【敏感資訊***脫敏】 綠底和紅字是分析文字

第一部分:犧牲品

第二部分:程序資訊

<process id="process40fb278"taskpriority="0" logused="144"waitresource="key: 5:72057594039238656 (61a06abd401c)"waittime="3421" ownerid="83492" transactionname="user_transaction" lasttranstarted="2018-01-31t00:19:12.110" xdes="0xa9ac290" lockmode="x" schedulerid="4" kpid="4312" status="suspended" spid="53" sbid="0" ecid="0" priority="0"trancount="2"locktimeout="4294967295" clientoption1="671090784" clientoption2="390200">

update [deadlocktest] set [num] = @1  where [id]=@2

update deadlocktest set num=100 where id=2

update deadlocktest set num=100 where id=2

<process id="process40eb468"taskpriority="0" logused="144"waitresource="key: 5:72057594039238656 (8194443284a0)"waittime="6676" ownerid="83494" transactionname="user_transaction" lasttranstarted="2018-01-31t00:19:14.247" xdes="0x4126378" lockmode="x" schedulerid="2" kpid="4340" status="suspended" spid="52" sbid="0" ecid="0" priority="0"trancount="2"

update [deadlocktest] set [num] = @1  where [id]=@2

update deadlocktest set num=100 where id=1

--commit     

begin tran

update deadlocktest set num=100 where id=2

update deadlocktest set num=100 where id=1

--commit

第三部分:資源資訊

hobtid="72057594039238656" dbid="5" objectname="blocktest.dbo.deadlocktest" indexname="pk_deadlocktest"id="lock2c69480" mode="x" associatedobjectid="72057594039238656">

<waiter id="process40fb278" mode="x" requesttype="wait"/>

根據上面的死鎖資訊,可以得到:

可以看到死鎖的原因,兩個事務都想獲取對方持有資源上的x鎖進行update,互不相讓,所以就形成了死鎖。

key: 5:72057594039238656   這個說明,鎖定的資源是key,資料庫是5,資源是72057594039238656

這些可以通過指令碼獲取到具體的資訊,但是沒有必要,第三部分resource-list完全可以獲取到,資料庫是blocktest,表示deadlocktest,鍵是pk_deadlocktest

解決方案,

由於兩個事務執行的sql順序相反,所以產生了這種情況,該case的解法就是將兩個事務sql執行順序設為一致即可。

四、死鎖總結

死鎖不能完全避免,只能是盡量降低,一般常用的方法【降低互斥發生的風險、減少鎖的申請數量、降低鎖持有的時間】:

1、按相同順序訪問物件

這樣就會降低互斥發生的風險,也就是demo的這個案例

2、事務盡量簡短

因為事務commit後,才會釋放該事務中持有的鎖,所以事務越簡短,持有鎖的時間就會越短,從而降低死鎖發生的概率。

3、優化sql,盡量避免table scan,index scan這種方式

這樣sql執行掃瞄/查詢的數量就會減少,從而達到減少申請鎖的數量的目的。

4、事務中避免與使用者的互動

這個會大大增長鎖持有的時間,demo的這個案例,也可以理解為與使用者互動了,因為事務1第二個update,測試時是等待第二個事務執行後,再去手動執行的。

還有乙個方法,就是降低事務的隔離級別,低隔離級別s鎖的持有時間會較短,但是這個方法大部分情況下是不可能採納的。

SQL Server的阻塞 死鎖問題

通過 sysprocesses 簡單查詢死鎖及解決死鎖辦法 簡單查詢死鎖,如下四步可以輕鬆解決 第一步 查詢死鎖語句 1 條件是 blocked 0 select dbid,from sys.sysprocesses where 1 1 and spid 50 and blocked 0 and s...

SQL Server 中的死鎖

在兩個或多個任務中,如果每個任務鎖定了其他的任務試圖鎖定的資源,會造成這些任務永久阻塞,從而出現死鎖。此時系統處於死鎖狀態。死鎖的原因 在多使用者環境下,死鎖的發生是由於兩個事物都鎖定了不同的資源而又都在申請對方鎖定的資源,即一組程序中的各個程序均占有不會釋放的資源,但因相互申請其他程序占用的不會釋...

sqlserver死鎖阻塞

create proc p lockinfo kill lock spid bit 1,是否殺掉死鎖的程序,1 殺掉,0 僅顯示 show spid if nolock bit 1 如果沒有死鎖的程序,是否顯示正常程序資訊,1 顯示,0 不顯示 as declare count int,s nvar...