減少SQL Server死鎖的方法
鎖是指在某組資源中,兩個或兩個以上的執行緒在執行過程中,在爭奪某一資源時而造成互相等待的現象,若無外力的作用下,它們都將無法推進下去,死時就可能會產生死鎖,這些永遠在互相等待的程式稱為死鎖執行緒。簡單的說,程式A等待程式B釋放他的資源,B又等待A釋放他的資源,這樣互相等待就形成死鎖。
如在資料庫中,如果需要對一條資料進行修改,首先資料庫管理系統會在上面加鎖,以保證在同一時間只有一個事務能進行修改操作。如事務1的執行緒 T1具有表A上的排它鎖,事務2的執行緒T2 具有表B上的排它鎖,並且之後需要表A上的鎖。事務2無法獲得這一鎖,因為事務1已擁有它。事務2被阻塞,等待事務1。然後,事務1需要表B的鎖,但無法獲得鎖,因為事務2將它鎖定了。事務在提交或回滾之前不能釋放持有的鎖。因為事務需要對方控制的鎖才能繼續操作,所以它們不能提交或回滾,這樣資料庫就會發生死鎖了。
如在編寫儲存過程的時候,由於有些儲存過程事務性的操作比較頻繁,如果先鎖住表A,再鎖住表B,那麼在所有的儲存過程中都要按照這個順序來鎖定它們。如果無意中某個儲存過程中先鎖定表B,再鎖定表A,這可能就會導致一個死鎖。而且死鎖一般是不太容易被發現的。
如果伺服器上經常出現這種死鎖情況,就會降低伺服器的效能,所以應用程式在使用的時候,我們就需要對其進行跟蹤,使用sp_who和sp_who2來確定可能是哪些使用者阻塞了其他使用者,我們還可以用下面的儲存過程來跟蹤具體的死鎖執行的影響:
create procedure sp_who_lock
as
begin
declare @spid int,@bl int,
@intTransactionCountOnEntry int,
@intRowcount int,
@intCountProperties int,
@intCounter int
create table #tmp_lock_who (id int identity(1,1),spid smallint,bl smallint)
IF @@ERROR<>0 RETURN @@ERROR
insert into #tmp_lock_who(spid,bl) select 0 ,blocked
from (select * from sysprocesses where blocked>0 ) a
where not exists(select * from (select * from sysprocesses where blocked>0 ) b
where a.blocked=spid)
union select spid,blocked from sysprocesses where blocked>0
IF @@ERROR<>0 RETURN @@ERROR
-- 找到臨時表的記錄數
select @intCountProperties = Count(*),@intCounter = 1
from #tmp_lock_who
IF @@ERROR<>0 RETURN @@ERROR
if @intCountProperties=0
select ’現在沒有阻塞和死鎖資訊’ as message
-- 迴圈開始
while @intCounter <= @intCountProperties
begin
-- 取第一條記錄
select @spid = spid,@bl = bl
from #tmp_lock_who where id = @intCounter
begin
if @spid =0
select ’引起資料庫死鎖的是: ’+ CAST(@bl AS VARCHAR(10)) + ’程式號,其執行的SQL語法如下’
else
select ’程式號SPID:’+ CAST(@spid AS VARCHAR(10))+ ’被’ + ’程式號SPID:’+ CAST(@bl AS VARCHAR(10)) +’阻塞,其當前程式執行的SQL語法如下’
DBCC INPUTBUFFER (@bl )
end
-- 迴圈指標下移
set @intCounter = @intCounter + 1
end
drop table #tmp_lock_who
return 0
end
我們只需要透過在查詢分析器裡面執行sp_who_lock,就可以具體捕捉到執行的堵塞程式,這時我們就可以對對應的SQL語句或者儲存過程進行效能上面的改進及設計。 [Page]
所以我們在資料庫設計的時候,雖然不能完全避免死鎖,但可以使死鎖的數量儘量減少。增加事務的吞吐量並減少系統開銷,因為只有很少的事務,所以就得遵循下面的原則:
按同一順序訪問物件
如果所有併發事務按同一順序訪問物件,則發生死鎖的可能性會降低。在寫SQL語句或儲存過程的時候,就需要按照順序在兩個併發事務中先獲得表A上的鎖,然後獲得表B上的鎖,當第一個事務完成之前,另一個事務被阻塞在表A上。第一個事務提交或回滾後,第二個事務繼續進行,而不能在語句裡面寫先獲得表B上的鎖,然後再獲得表A的鎖。
避免事務中的使用者互動
避免編寫包含使用者互動的事務,因為執行沒有使用者互動的批處理的速度要遠遠快於使用者手動響應查詢的速度,例如答覆應用程式請求引數的提示。例如,如果事務正在等待使用者輸入,而使用者就去做別的事了,則使用者將此事務掛起使之不能完成。這樣將降低系統的吞吐量,因為事務持有的任何鎖只有在事務提交或回滾時才會釋放。即使不出現死鎖的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。
保持事務簡短並在一個批處理中
在同一資料庫中併發執行多個需要長時間執行的事務時通常發生死鎖。事務執行時間越長,其持有排它鎖或更新鎖的時間也就越長,從而堵塞了其它活動並可能導致死鎖。保持事務在一個批處理中,可以最小化事務的網路通訊往返量,減少完成事務可能的延遲並釋放鎖。
使用低隔離級別
確定事務是否能在更低的隔離級別上執行。執行提交讀允許事務讀取另一個事務已讀取(未修改)的資料,而不必等待第一個事務完成。使用較低的隔離級別(例如提交讀)而不使用較高的隔離級別(例如可序列讀)可以縮短持有共享鎖的時間,從而降低了鎖定爭奪。
使用繫結連線
使用繫結連線使同一應用程式所開啟的兩個或多個連線可以相互合作。次級連線所獲得的任何鎖可以象由主連線獲得的鎖那樣持有,反之亦然,因此不會相互阻塞。
下面有一些對死鎖發生的一些建議:
1)對於頻繁使用的表使用集簇化的索引;
2)設法避免一次性影響大量記錄的T-SQL語句,特別是INSERT和UPDATE語句;
3)設法讓UPDATE和DELETE語句使用索引;
4)使用巢狀事務時,避擴音交和回退衝突;
5)對一些資料不需要及時讀取更新值的表在寫SQL的時候在表後臺加上(nolock),如:Select * from tableA(nolock) 。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/66009/viewspace-1029648/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQL Server 的死鎖SQLServer
- SQL SERVER死鎖查詢,死鎖分析,解鎖,查詢佔用SQLServer
- 減少該死的 if else 巢狀巢狀
- SQL Server 資料庫查詢死鎖的處理步驟SQLServer資料庫
- 如何捕獲和記錄SQL Server中發生的死鎖SQLServer
- 在 SQL Server 中查詢活動連線和死鎖SQLServer
- 減少程式碼中該死的 if else 巢狀巢狀
- 怎麼減少行鎖對效能的影響?
- [翻譯]:SQL死鎖-阻塞探測SQL
- Sql Server深入的探討鎖機制SQLServer
- 前端頁面優化,減少 reflow 的方法前端優化
- 作業系統(5) 死鎖的概念 死鎖產生的必要條件 死鎖的處理策略 預防死鎖 避免死鎖 死鎖的檢測和解除 銀行家演算法作業系統演算法
- SQL Server有關鎖升級的誤區說明SQLServer
- 死鎖
- 常見的死鎖情況及解決方法
- 鎖的使用與死鎖的避免
- [轉帖]SQL Server 鎖機制 悲觀鎖 樂觀鎖 實測解析SQLServer
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- MySQL:一個死鎖分析 (未分析出來的死鎖)MySql
- Webpack + Vue,部署時減少包體積的幾種方法WebVue
- Java 中的死鎖Java
- SQLServer 如何收集資料以排除 SQL 死鎖問題SQLServer
- 面試官:請用SQL模擬一個死鎖面試SQL
- SQLServer的死鎖分析(1):頁鎖SQLServer
- 什麼是死鎖?如何解決死鎖?
- 簡單介紹MySQL列印死鎖日誌的方法MySql
- 面試官:什麼是死鎖?怎麼排查死鎖?怎麼避免死鎖?面試
- 死鎖概述
- SQL Server各種日期計算方法SQLServer
- 減少Android APK的大小99.99%AndroidAPK
- 檢視oracle死鎖程式並結束死鎖Oracle
- 例項詳解 Java 死鎖與破解死鎖Java
- 前端開發中減少重複勞動,提升效率的方法前端
- 死鎖和可重入鎖
- MySQL 死鎖和鎖等待MySql
- Slave SQL執行緒與PXB FTWRL死鎖問題分析SQL執行緒
- 剖析6個MySQL死鎖案例的原因以及死鎖預防策略MySql
- 在rhel和CentOS上安裝SQL Server的方法CentOSSQLServer
- MySQL死鎖系列-線上死鎖問題排查思路MySql