初涉SQL Server性能問題(2/4):列出等待資源的會話

初涉SQL Server性能問題(1/4)裏,咱們知道了如何快速檢查服務器實例上正運行的任務數和IO等待的任務數。這個是輕量級的腳本,不會給服務器形成任何壓力,即便服務器在高負荷下,也能夠正常得到結果。html

問題檢測的第2步是獲取在進行任何資源等待的會話。下面的腳本會幫助咱們得到這些信息。這個查詢須要預創建一個函數,若是會話是由SQL Server代理啓動的話,會顯示具體的做業名。node

 

 1 /*****************************************************************************************
 2            PREREQUISITE FUNCTION
 3 ******************************************************************************************/
 4 USE MASTER
 5 GO 
 6 CREATE FUNCTION ConvertStringToBinary  ( @hexstring  VARCHAR(100)
 7 )  RETURNS BINARY(34)  AS
 8 BEGIN
 9 
10    RETURN(SELECT CAST('' AS XML).value('xs:hexBinary( substring(sql:variable("@hexstring"), sql:column("t.pos")) )', 'varbinary(max)')
11    FROM (SELECT CASE SUBSTRING(@hexstring, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos))  
12 END
13 /***************************************************************************************
14 STEP 2: List the session which are currently waiting for resource
15 ****************************************************************************************/
16 SELECT node.parent_node_id AS Node_id,
17 es.HOST_NAME,
18 es.Login_name,
19 CASE WHEN es.program_name LIKE '%SQLAgent - TSQL JobStep%' THEN
20          (
21           SELECT 'SQL AGENT JOB: '+name FROM msdb..sysjobs WHERE job_id=
22           MASTER.DBO.ConvertStringToBinary (LTRIM(RTRIM((SUBSTRING(es.program_name,CHARINDEX('(job',es.program_name,0)+4,35)))))
23           )
24     ELSE es.program_name END  AS [Program Name] ,
25 DB_NAME(er.database_id) AS DatabaseName,
26 er.session_id, 
27 wt.blocking_session_id,
28 wt.wait_duration_ms,
29 wt.wait_type,
30 wt.NoThread ,
31 er.command,
32 er.status,
33 er.wait_resource,
34 er.open_transaction_count,
35 er.cpu_time,
36 er.total_elapsed_time AS ElapsedTime_ms,
37 er.percent_complete ,
38 er.reads,
39 er.writes,
40 er.logical_reads,
41 wlgrp.name AS ResoursePool              ,
42 SUBSTRING   (sqltxt.TEXT,(er.statement_start_offset/2) + 1,          
43             ((CASE WHEN er.statement_end_offset = -1          
44              THEN LEN(CONVERT(NVARCHAR(MAX), sqltxt.TEXT)) * 2          
45              ELSE er.statement_end_offset          
46             END - er.statement_start_offset)/2) + 1) AS [Individual Query], 
47 sqltxt.TEXT AS [Batch Query]                
48 FROM (SELECT session_id, SUM(wait_duration_ms) AS 
49 wait_duration_ms,wait_type,blocking_session_id,COUNT(*) AS NoThread 
50 FROM  SYS.DM_OS_WAITING_TASKS  GROUP BY session_id, wait_type,blocking_session_id) wt 
51 INNER JOIN SYS.DM_EXEC_REQUESTS  er ON wt.session_id=er.session_id INNER JOIN SYS.DM_EXEC_SESSIONS es ON es.session_id= er.session_id
52 INNER JOIN SYS.DM_RESOURCE_GOVERNOR_WORKLOAD_GROUPS wlgrp ON wlgrp.group_id=er.group_id          
53 INNER JOIN  (SELECT  os.parent_node_id ,task_address FROM SYS.DM_OS_SCHEDULERS  OS INNER JOIN 
54 SYS.DM_OS_WORKERS  OSW ON OS.scheduler_address=OSW.scheduler_address 
55 WHERE os.status='VISIBLE ONLINE' GROUP BY os.parent_node_id ,task_address ) node   
56 ON node.task_address=er.task_address
57 CROSS APPLY SYS.DM_EXEC_SQL_TEXT(er.sql_handle) AS sqltxt
58 WHERE sql_handle IS NOT NULL AND wt.wait_type NOT IN ('WAITFOR','BROKER_RECEIVE_WAITFOR')
59 GO
View Code

 

輸出結果的每列說明介紹以下:sql

  • Node_id  NUMA節點ID。能夠被調度者查詢的節點映射。
  • HOST_NAME 創建鏈接的計算機名。
  • Login_name 鏈接到數據庫服務器的會話用戶名。
  • Program Name 使用會話的對應程序名。在鏈接字符串裏能夠設置程序名。若是會話是SQL Server代理的一部分,則顯示做業名。
  • DatabaseName 會話的當前數據庫名。
  • session_id 會話ID。
  • blocking_session_id 阻塞語句的會話ID。
  • wait_duration_ms 等待時間,單位爲毫秒。這個時間不包括信號等待時間(signal wait time )。
  • wait_type 等待類型名稱,例如:SLEEP_TASK,CXPACKET等。
  • NoThread 當前會話的線程數,若是當前會話是並行執行(parallel execution)的話。
  • command 標識當前類型的命令,即T-SQL語句,例如Select,insert,update,delete等。
  • status 請求狀態:Background,Running,Runnable,Sleeping 和 Suspended。
  • wait_resource 請求當前等待的資源。
  • open_transaction_count 當前會話打開的事務數。
  • cpu_time 請求使用的CPU時間,單位毫秒。
  • ElapsedTime_ms 自請求到達後,佔用的CPU時間,單位毫秒。
  • percent_complete 指定操做的工做完成進度,例如備份、還原、回滾等。
  • reads 請求執行的讀數。
  • writes 請求執行的寫數。
  • logical_reads 請求執行的邏輯讀數。
  • ResoursePool 資源管理池名稱。
  • Individual Query 在會話裏運行的批處理SQL語句。
  • Batch Query 在會話裏運行的批處理(存儲過程/一系列的語句)。

上述查詢屢次執行後,輸出結果有很長wait_duration_ms的會話,這個會話不被其餘會話阻塞,且一直在輸出結果裏。咱們就要看看這個會話的程序名,主機名,登陸用戶名,還有對應的執行語句,具體進行什麼操做形成的。根據這些信息,咱們能夠選擇性的去終止這個會話,而後分析下具體的執行語句。若是會話是被阻塞的,咱們要用另外的語句來找出阻塞的會話。數據庫

第3步,列出服務器上正運行的會話清單。服務器

 

 1 /***************************************************************************************
 2 STEP 3: List the session which are currently waiting/running
 3 ****************************************************************************************/
 4 SELECT node.parent_node_id AS Node_id,
 5 es.HOST_NAME,
 6 es.login_name,
 7 CASE WHEN es.program_name LIKE '%SQLAgent - TSQL JobStep%' THEN
 8 (SELECT 'SQL AGENT JOB: '+name FROM msdb..sysjobs WHERE job_id=DBO.ConvertStringToBinary (LTRIM(RTRIM((SUBSTRING(es.program_name,CHARINDEX('(job',es.program_name,0)+4,35)))))
 9 )ELSE es.program_name END  AS program_name ,
10 DB_NAME(er.database_id) AS DatabaseName,
11 er.session_id, 
12 wt.blocking_session_id,
13 wt.wait_duration_ms,
14 wt.wait_type,
15 wt.NoThread ,
16 er.command,
17 er.status,
18 er.wait_resource,
19 er.open_transaction_count,
20 er.cpu_time,
21 er.total_elapsed_time AS ElapsedTime_ms,
22 er.percent_complete ,
23 er.reads,er.writes,er.logical_reads,
24 wlgrp.name AS ResoursePool              ,
25 SUBSTRING (sqltxt.TEXT,(er.statement_start_offset/2) + 1,                
26 ((CASE WHEN er.statement_end_offset = -1                
27 THEN LEN(CONVERT(NVARCHAR(MAX), sqltxt.TEXT)) * 2                
28 ELSE er.statement_end_offset                
29 END - er.statement_start_offset)/2) + 1) AS [Individual Query],
30 sqltxt.TEXT AS [Batch Query]                
31 FROM 
32 SYS.DM_EXEC_REQUESTS  er INNER JOIN SYS.DM_EXEC_SESSIONS es ON es.session_id= er.session_id
33 INNER JOIN SYS.DM_RESOURCE_GOVERNOR_WORKLOAD_GROUPS wlgrp ON wlgrp.group_id=er.group_id          
34 INNER JOIN  (SELECT  os.parent_node_id ,task_address FROM SYS.DM_OS_SCHEDULERS  OS 
35 INNER JOIN SYS.DM_OS_WORKERS  OSW ON OS.scheduler_address=OSW.scheduler_address
36 WHERE os.status='VISIBLE ONLINE' GROUP BY os.parent_node_id ,task_address ) node ON node.task_address=er.task_address
37 LEFT JOIN 
38 (SELECT session_id, SUM(wait_duration_ms) AS 
39 wait_duration_ms,wait_type,blocking_session_id,COUNT(*) AS NoThread 
40 FROM  SYS.DM_OS_WAITING_TASKS  GROUP BY session_id, wait_type,blocking_session_id) wt 
41 ON wt.session_id=er.session_id
42 CROSS apply SYS.DM_EXEC_SQL_TEXT(er.sql_handle) AS sqltxt
43 WHERE sql_handle IS NOT NULL AND ISNULL(wt.wait_type ,'') NOT IN 
44 ('WAITFOR','BROKER_RECEIVE_WAITFOR')
45 ORDER BY er.total_elapsed_time DESC
46 
47 GO
View Code

 

 

 

這裏的輸出列和第2步徹底相同,我會分析total_elapsed_time佔用時間較長的會話,酌情考慮是否終止這些會話,並分析下對應的執行SQL語句。大多數狀況下(服務器一致運行穩定,忽然卡住了),使用上述步驟就能夠解決問題。下一篇文章咱們會看下阻塞的會話,還有打開未活動事務的會話。 session

相關文章
相關標籤/搜索