1. 程式人生 > >sql server 性能調優之 資源等待 LCk

sql server 性能調優之 資源等待 LCk

bsp HERE 設置 sel begin lock enter runnable waiting

原文:sql server 性能調優之 資源等待 LCk

一. 概述

  這次介紹實例級別資源等待LCK類型鎖的等待時間,關於LCK鎖的介紹可參考 “sql server 鎖與事務撥雲見日”。下面還是使用sys.dm_os_wait_stats 來查看,並找出耗時最高的LOK鎖。

select wait_type,
waiting_tasks_count,
wait_time_ms ,
max_wait_time_ms,
signal_wait_time_ms
from sys.dm_os_wait_stats
where wait_type like
LCK% order by wait_time_ms desc

查出如下圖所示:

技術分享圖片

1. 分析介紹

  重點介紹幾個耗時最高的鎖含義:

  LCK_M_IX: 正在等待獲取意向排它鎖。在增刪改查中都會有涉及到意向排它鎖。
  LCK_M_U: 正在等待獲取更新鎖。 在修改刪除都會有涉及到更新鎖。
  LCK_M_S:正在等待獲取共享鎖。 主要是查詢,修改刪除也都會有涉及到共享鎖。
  LCK_M_X:正在等待獲取排它鎖。在增刪改中都會有涉及到排它鎖。
  LCK_M_SCH_S:正在等待獲取架構共享鎖。防止其它用戶修改如表結構。
  LCK_M_SCH_M:正在等待獲取架構修改鎖 如添加列或刪除列 這個時候使用的架構修改鎖。

下面表格是統計分析

鎖類型 鎖等待次數 鎖等待總時間(秒) 平均每次等待時間(毫秒) 最大等待時間
LCK_M_IX 26456 5846.871 221 47623
LCK_M_U 34725 425.081 12 6311
LCK_M_S 613 239.899 391 4938
LCK_M_X 4832 77.878 16 4684
LCK_M_SCH_S 397 77.832 196 6074
LCK_M_SCH_M 113 35.783 316 2268

  註意: wait_time_ms 時間裏,該時間表包括了signal_wait_time_ms信號等待時間,也就是說wait_time_ms不僅包括了申請鎖需要的等待時間,還包括了線程Runnable 的信號等待。通過這個結論也能得出max_wait_time_ms 最大等待時間不僅僅只是鎖申請需要的等待時間。

2. 重現鎖等待時間

--  重置
DBCC SQLPERF (sys.dm_os_wait_stats, CLEAR);  

 技術分享圖片

--  會話1 更新SID=92525000, 未提交
begin tran 
update [dbo].[PUB_StockTestbak] set model=mmtest where sid=92525000
-- 會話2 查詢該ID, 由於會話1更新未提交 占用x鎖,這裏查詢將阻塞
select * from [PUB_StockTestbak] where sid=92525000

  手動取消會話2的查詢,占用時間是61秒,如下圖:

技術分享圖片

  再來統計資源等待LCK,如下圖 :

技術分享圖片

  總結:可以看出資源等待LCK的統計信息還是非常正確的。所以找出性能消耗最高的鎖類型,去優化是很有必要。比較有針對性的解決阻塞問題。

3. 造成等待的現象和原因

現象:

  (1) 用戶並發越問越多,性能越來越差。應用程序運行很慢。

  (2) 客戶端經常收到錯誤 error 1222 已超過了鎖請求超時時段。

  (3) 客戶端經常收到錯誤 error 1205 死鎖。

  (4) 某些特定的sql 不能及時返回應用端。

原因:

  (1) 用戶並發訪問越多,阻塞就會越來越多。

  (2) 沒有合理使用索引,鎖申請的數量多。

  (3) 共享鎖沒有使用nolock, 查詢帶來阻塞。 好處是必免臟讀。

  (4) 處理的數據過大。比如:一次更新上千條,且並發多。

  (5) 沒有選擇合適的事務隔離級別,復雜的事務處理等。

4. 優化鎖的等待時間

   在優化鎖等待優化方面,有很多切入點 像前幾篇中有介紹 CPU和I/O的耗時排查和處理方案。 我們也可以自己寫sql來監聽鎖等待的sql 語句。能夠知道哪個庫,哪個表,哪條語句發生了阻塞等待,是誰阻塞了它,阻塞的時間。

  從上面的平均每次等待時間(毫秒),最大等待時間 作為參考可以設置一個閥值。 通過sys.sysprocesses 提供的信息來統計, 關於sys.sysprocesses使用可參考 "sql server 性能調優 從用戶會話狀態分析"。 通過該視圖 監聽一段時間內的阻塞信息。可以設置每10秒跑一次監聽語句,把阻塞與被阻塞存儲下來。

  思想如下:

-- 例如 找出被阻塞會話ID 如時間上是2秒 以及誰阻塞了它的會話ID
SELECT spid,blocked #monitorlock FROM sys.sysprocesses 
where blocked>0 and    waittime>2000 

-- 通過while或遊標來一行行獲取臨時表的 會話ID,阻塞ID,通過exec動態執行來獲取sql語句文本 進行存儲
exec(DBCC INPUTBUFFER(+@spid+)) 

exec(‘DBCC INPUTBUFFER(‘+@blocked+‘)‘)

sql server 性能調優之 資源等待 LCk