Expert 診斷優化系列------------------鎖是個大角色
前面幾篇已經陸續從伺服器的幾個大塊講述了SQL SERVER資料庫的診斷和調優方式。加上本篇可以說已經可以完成常規的問題診斷及優化,本篇就是SQL SERVER中的鎖。為了方便閱讀給出系列文章的導讀連結:
首先閱讀本文之前,大家都應該知道鎖是影響你效能的一個重大因素,那麼SQL SERVER為什麼要引入鎖呢?那就是要解決多個使用者同時對資料庫的併發操作時會帶來以下資料不一致的問題。我想為了保證資料一致性,哪怕犧牲再多也是值得的!本文主要介紹怎麼找到這個犧牲的點,及如何讓你的犧牲降到最低!
還記得等待篇中的那個北京三環麼?
等待很多時候都是在等待獲取物件上的鎖!當資料庫中出現很多很多鎖時,系統瞬間就無法提供正常服務。此時觀察系統資源的使用情況,會發現CPU使用率不高,記憶體佔用量也不高,還有很多未使用的記憶體,網路頻寬也充足,硬碟也不繁忙,通過資料庫管理工具查詢的話,SQL SERVER中的資料也正常無誤,但是使用系統的使用者訪問此資料庫時卻要需要等很多久很久,更多的就出現連線超時,資料庫無響應。
這就好比本來就是早高峰,前面還撞了!十一車連撞很壯觀,對於資料庫十一條連鎖,也很給力!
--------------部落格地址---------------------------------------------------------------------------------------
廢話不多說,直接開整-----------------------------------------------------------------------------------------
鎖造成的等待主要有兩種:和 LCK_ 和 PAGELATCH_
PAGELATCH_:輕量級資料庫內部使用的閂鎖,這裡不介紹
LCK_ : 八斤半的大鎖這裡就說它!
注 : 鎖相關的基礎知識請自行百度學習!
-
診斷鎖常用的效能計數器
- Lock Requests/sec 每秒鎖請求數
- Lock Waits/sec 每秒鎖等待數
- Lock Wait Time (ms) 鎖等待時間
- Average Wait Time (ms) 平均等待時間
- Number of Deadlocks/sec 每秒死鎖數
- Latch Waits/sec 閂鎖等待數
- Average Latch Wait Time (ms) 閂鎖平均等待時間
計數器不過多介紹,不會用的朋友請自行百度。直接上例子:
這個例子中客戶反映特定時間點系統特別慢嚴重影響業務,那麼我們按常規順序進行一次全面分析。
CPU來看在10點左右和晚上6點左右出現90%以上的高峰。
頁生命週期和惰性寫入器可以看出記憶體並無明顯的壓力
以10點為例(為什麼不看六點?我默默地分析過是一樣的情況)磁碟佇列並不高,但10點15分的時候出現磁碟高壓力。那麼這是一個問題導致的還是兩個呢?我們接著看。
事務活動數在10點的時候達到一個很高的值。
使用者連線數在10點也彪高,那麼問題清楚了,就是10點時候是使用者連線太多了壓力大了導致系統慢的!別天真了這篇主題是鎖,主角還沒出場怎麼能結束? 反覆強調不要輕易下結論!
連線數量多,還一個原因就是連線執行語句的時間長很長時間才能釋放,那麼其他的應用只能開啟新連線,所以連線數會彪高,
log重新整理數量彪高這時間點在insert、delete或update?(後文證實是update)
-----------------------------------------下面進入正題了--------------------
我大量update系統會很慢?會跑不動?
我們看下鎖相關的計數器
鎖請求數! 這個時間點大量的鎖請求產生!
鎖等待,大量鎖等待
再看等待時間,高峰點已經達到了70秒!! 要等待70秒是啥概念? 簡直是高考學校門口,還是個早高峰!!
天啊,還好沒有死鎖....
------------------------------語句及等待診斷--------------------
我通過計數器可以發現2個主要問題:1. 十點的時候大量update更新,導致系統大面積阻塞,語句執行時間過長。2.十點15分以後有大量磁碟讀操作,導致磁碟佇列暴增。
下面我們看一下語句和等待的情況:
語句和等待總體反應情況很正常,長時間語句少,而且等待並不嚴重。那麼說明,這麼系統問題點就是在特定時間點(這也是使用者反應的系統慢的原因,開篇就已經提過)
那下面我們就深入10點,看看那時候到底怎麼了!
首先 我們先看看語句情況!
上面圖中我們只是展示了問題時點的一部分語句,主要可以看出如下結論:
- 問題時間點確實有大量的更新操作
- 更新操作被嚴重阻塞(鎖)
- 且是一個程式迴圈呼叫的更新
- 語句執行時間長
- CPU高是因為這個時間點除了update以外還有大量的查詢導致CPU高(一般情況下,系統大面積鎖等待的時候CPU 資源不能有效利用,CPU會低)
接著我們看一下等待的情況,看看到底是怎麼搞得,竟然鎖的這麼厲害!
語句總體等待來看全天都有但十點大量,並且造成系統卡死(預設30秒超時,很多都應該超時了,所以使用者體驗非常差!),語句的CPU和讀寫都不多,也說明就是相互鎖的很嚴重!
大量的語句都是被195鎖住的,而195其實本身也是同樣的一個update,客戶的程式中有頻繁的這條update,並且在10點的時候會有另一個程式的一次大批量的迴圈更新,這也是造成這個大面積鎖阻塞的原因!
這個問題的一個最終解決辦法就是修改這個大批的迴圈更新,首先把每個單次處理和計算的結果進行統一計算,在做一次批量更新。這樣既縮短事務的時間,降低鎖定的時間。同時也降低了整個批語句的執行時間!
類似以SQL 中的遊標,和程式中的for 迴圈單條操作,都可以修改成批量處理,不僅可以減少事務長度,減少鎖時間,更是一種很有效的優化手段 !
第二個問題,磁碟10點15為什麼那麼高?和更新有關係?
這裡可以看出第二個問題10點15的時候確實有很多大邏輯讀的查詢,還跟新沒什麼關係,但和業務有無關聯就不得而知了。導致系統磁碟壓力變大,和主題關係不大這裡不說了..
-
關於鎖的一個小誤區
select 會阻塞 update 麼? (這裡指的是預設隔離級別,read committed)
上段簡單小程式碼
create table a (a int) insert into a select OBJECT_ID from sys.objects where object_id between 1 and 1000 begin tran select * from a with(holdlock) where a = 3 --------------新開一個session 執行 update a set a = 30 where a = 3
這裡的with(holdlock) 是讓查詢保持S鎖,模擬你的查詢還沒結束。
sp_who2 或 select session_id,status,command,blocking_session_id,wait_type from sys.dm_exec_requests where session_id = 58 檢視一下
高能預警: 查詢也會阻塞更新的哦~~
--------------部落格地址---------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
總結:語句執行時間長,很可能的一個原因就是阻塞導致的,而阻塞大部分情況都是因為資源之間的所等待。
語句調優的時候有必要對系統做一個全面的分析。(如本文所講)
鎖的優化可以說是比較深入問題分析,減少鎖的相互影響,主要也可以從語句優化入手,降低消耗縮短時間。另外也可以從業務設計方面入手,降低熱點資源的爭用。
鎖主要是為了維護資料一致性而不得不做的犧牲。我們只能盡一切辦法降低他的影響。
PS:限於篇幅本文沒有講述一些基本知識,請自行學習,如隔離級別、鎖矩陣相容性等等.....
----------------------------------------------------------------------------------------------------
注:此文章為原創,歡迎轉載,請在文章頁面明顯位置給出此文連結!
若您覺得這篇文章還不錯請點選下右下角的推薦,非常感謝!
為了方便閱讀給出系列文章的導讀連結: