[SQL]監看 TempDB 的狀況

[SQL]監看 TempDB 的狀況

最近跟朋友討論到如何去監看 TempDB 一下子爆增的情況,要找出到底那個Session去把它給搞大的。

所以google了一下,看到這篇「SQL Server Tempdb Usage and Bottlenecks tracked with Extended Events」,非常建議大家看一下。

個人將重點整理如下,
如果您的DB是SQL 2005的話,可以用以下的DMV來看TempDB(有Block,所以如果沒有Block的話,就找不出來!)


--Look for PFS and GAM pages '2:1:1' and '2:1:3'
--'2:1:1'/'2:1:3' is really 2: tempdb, 1: file number, 1: PFS, 3: GAM
SELECT 
   session_id
   , wait_duration_ms
   , resource_description
FROM sys.dm_os_waiting_tasks
WHERE wait_type LIKE 'PAGE%LATCH_%' AND Resource_description LIKE '2.%'

以上的SQL是看執行SQL目前的狀況,所以如果要看以前的狀況,則要看 sys.dm_os_wait_stats 。

但 sys.dm_os_wait_stats 只提供統計資訊,所以無法得知,到底是那個 Session 搞的。

 

因為SQL 2005沒有 Extended Events,SQL 2008(含)以後才有。所以在SQL 2008時,我們可以建立去監看 TempDB 的 Extended Events,如下,


--Drop the event if it already exists
DROP EVENT SESSION Monitor_wait_info_tempdb ON SERVER; 
GO 
--Create the event 
CREATE EVENT SESSION Monitor_wait_info_tempdb ON SERVER 
--We are looking at wait info only
ADD EVENT sqlos.wait_info
( 
   --Add additional columns to track
   ACTION (sqlserver.database_id, sqlserver.sql_text, sqlserver.session_id, sqlserver.tsql_stack)  
    WHERE sqlserver.database_id = 2 --filter database id = 2 i.e tempdb
    --This allows us to track wait statistics at database granularity
) --As a best practise use asynchronous file target, reduces overhead.
ADD TARGET package0.asynchronous_file_target(
     SET filename='c:\Monitor_wait_info_tempdb.etl', metadatafile='c:\Monitor_wait_info_tempdb.mta')
GO
--Now start the session
ALTER EVENT SESSION Monitor_wait_info_tempdb ON SERVER
STATE = START;
GO

以上SQL,filename請依環境不同來調整它。

 

建立好 Extended Events 後,就可以查看 TempDB 透過以下的SQL來查看這些記錄,如下,


SELECT wait_typeName 
      , SUM(total_duration) AS total_duration
      , SUM(signal_duration) AS total_signal_duration
FROM (
SELECT
  FinalData.R.value ('@name', 'nvarchar(50)') AS EventName,  
  FinalData.R.value ('data(data/value)[1]', 'nvarchar(50)') AS wait_typeValue,
  FinalData.R.value ('data(data/text)[1]', 'nvarchar(50)') AS wait_typeName,
  FinalData.R.value ('data(data/value)[5]', 'int') AS total_duration,
  FinalData.R.value ('data(data/value)[6]', 'int') AS signal_duration,
  FinalData.R.value ('(action/.)[1]', 'nvarchar(50)') AS DatabaseID,
  FinalData.R.value ('(action/.)[2]', 'nvarchar(50)') AS SQLText,
  FinalData.R.value ('(action/.)[3]', 'nvarchar(50)') AS SessionID
FROM
( SELECT CONVERT(xml, event_data) AS xmldata
   FROM sys.fn_xe_file_target_read_file
   ('c:\Monitor_wait_info_tempdb*.etl', 'c:\Monitor_wait_info_tempdb*.mta', NULL, NULL)
) AsyncFileData
CROSS APPLY xmldata.nodes ('//event') AS FinalData (R)) xyz
WHERE wait_typeName NOT IN ('SLEEP_TASK')
 GROUP BY wait_typeName
 ORDER BY total_duration

以上是彙整資訊,如果要看單個Session資訊的話,就將中間的SQL抽出來Run就可以了,如下,


SELECT
  FinalData.R.value ('@name', 'nvarchar(50)') AS EventName,  
  FinalData.R.value ('data(data/value)[1]', 'nvarchar(50)') AS wait_typeValue,
  FinalData.R.value ('data(data/text)[1]', 'nvarchar(50)') AS wait_typeName,
  FinalData.R.value ('data(data/value)[5]', 'int') AS total_duration,
  FinalData.R.value ('data(data/value)[6]', 'int') AS signal_duration,
  FinalData.R.value ('(action/.)[1]', 'nvarchar(50)') AS DatabaseID,
  FinalData.R.value ('(action/.)[2]', 'nvarchar(4000)') AS SQLText,
  FinalData.R.value ('(action/.)[3]', 'nvarchar(50)') AS SessionID
FROM
( SELECT CONVERT(xml, event_data) AS xmldata
   FROM sys.fn_xe_file_target_read_file
   ('c:\Monitor_wait_info_tempdb*.etl', 'c:\Monitor_wait_info_tempdb*.mta', NULL, NULL)
) AsyncFileData
CROSS APPLY xmldata.nodes ('//event') AS FinalData (R) 
ORDER BY total_duration DESC

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^