初涉SQL Server性能问题(2/4):列出等待资源的会话
2015-06-01 13:42
323 查看
在初涉SQL Server性能问题(1/4)里,我们知道了如何快速检查服务器实例上正运行的任务数和IO等待的任务数。这个是轻量级的脚本,不会给服务器造成任何压力,即使服务器在高负荷下,也可以正常获得结果。
问题检测的第2步是获取在进行任何资源等待的会话。下面的脚本会帮助我们获得这些信息。这个查询需要预建立一个函数,如果会话是由SQL Server代理启动的话,会显示具体的作业名。
输出结果的每列说明介绍如下:
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步,列出服务器上正运行的会话清单。
这里的输出列和第2步完全相同,我会分析total_elapsed_time占用时间较长的会话,酌情考虑是否终止这些会话,并分析下对应的执行SQL语句。大多数情况下(服务器一致运行稳定,突然卡住了),使用上述步骤就可以解决问题。下一篇文章我们会看下阻塞的会话,还有打开未活动事务的会话。
问题检测的第2步是获取在进行任何资源等待的会话。下面的脚本会帮助我们获得这些信息。这个查询需要预建立一个函数,如果会话是由SQL Server代理启动的话,会显示具体的作业名。
/***************************************************************************************** PREREQUISITE FUNCTION ******************************************************************************************/ USE MASTER GO CREATE FUNCTION ConvertStringToBinary ( @hexstring VARCHAR(100) ) RETURNS BINARY(34) AS BEGIN RETURN(SELECT CAST('' AS XML).value('xs:hexBinary( substring(sql:variable("@hexstring"), sql:column("t.pos")) )', 'varbinary(max)') FROM (SELECT CASE SUBSTRING(@hexstring, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos)) END /*************************************************************************************** STEP 2: List the session which are currently waiting for resource ****************************************************************************************/ SELECT node.parent_node_id AS Node_id, es.HOST_NAME, es.Login_name, CASE WHEN es.program_name LIKE '%SQLAgent - TSQL JobStep%' THEN ( SELECT 'SQL AGENT JOB: '+name FROM msdb..sysjobs WHERE job_id= MASTER.DBO.ConvertStringToBinary (LTRIM(RTRIM((SUBSTRING(es.program_name,CHARINDEX('(job',es.program_name,0)+4,35))))) ) ELSE es.program_name END AS [Program Name] , DB_NAME(er.database_id) AS DatabaseName, er.session_id, wt.blocking_session_id, wt.wait_duration_ms, wt.wait_type, wt.NoThread , er.command, er.status, er.wait_resource, er.open_transaction_count, er.cpu_time, er.total_elapsed_time AS ElapsedTime_ms, er.percent_complete , er.reads, er.writes, er.logical_reads, wlgrp.name AS ResoursePool , SUBSTRING (sqltxt.TEXT,(er.statement_start_offset/2) + 1, ((CASE WHEN er.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), sqltxt.TEXT)) * 2 ELSE er.statement_end_offset END - er.statement_start_offset)/2) + 1) AS [Individual Query], sqltxt.TEXT AS [Batch Query] FROM (SELECT session_id, SUM(wait_duration_ms) AS wait_duration_ms,wait_type,blocking_session_id,COUNT(*) AS NoThread FROM SYS.DM_OS_WAITING_TASKS GROUP BY session_id, wait_type,blocking_session_id) wt 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 INNER JOIN SYS.DM_RESOURCE_GOVERNOR_WORKLOAD_GROUPS wlgrp ON wlgrp.group_id=er.group_id INNER JOIN (SELECT os.parent_node_id ,task_address FROM SYS.DM_OS_SCHEDULERS OS INNER JOIN SYS.DM_OS_WORKERS OSW ON OS.scheduler_address=OSW.scheduler_address WHERE os.status='VISIBLE ONLINE' GROUP BY os.parent_node_id ,task_address ) node ON node.task_address=er.task_address CROSS APPLY SYS.DM_EXEC_SQL_TEXT(er.sql_handle) AS sqltxt WHERE sql_handle IS NOT NULL AND wt.wait_type NOT IN ('WAITFOR','BROKER_RECEIVE_WAITFOR') GO
输出结果的每列说明介绍如下:
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步,列出服务器上正运行的会话清单。
/*************************************************************************************** STEP 3: List the session which are currently waiting/running ****************************************************************************************/ SELECT node.parent_node_id AS Node_id, es.HOST_NAME, es.login_name, CASE WHEN es.program_name LIKE '%SQLAgent - TSQL JobStep%' THEN (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))))) )ELSE es.program_name END AS program_name , DB_NAME(er.database_id) AS DatabaseName, er.session_id, wt.blocking_session_id, wt.wait_duration_ms, wt.wait_type, wt.NoThread , er.command, er.status, er.wait_resource, er.open_transaction_count, er.cpu_time, er.total_elapsed_time AS ElapsedTime_ms, er.percent_complete , er.reads,er.writes,er.logical_reads, wlgrp.name AS ResoursePool , SUBSTRING (sqltxt.TEXT,(er.statement_start_offset/2) + 1, ((CASE WHEN er.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), sqltxt.TEXT)) * 2 ELSE er.statement_end_offset END - er.statement_start_offset)/2) + 1) AS [Individual Query], sqltxt.TEXT AS [Batch Query] FROM SYS.DM_EXEC_REQUESTS er INNER JOIN SYS.DM_EXEC_SESSIONS es ON es.session_id= er.session_id INNER JOIN SYS.DM_RESOURCE_GOVERNOR_WORKLOAD_GROUPS wlgrp ON wlgrp.group_id=er.group_id INNER JOIN (SELECT os.parent_node_id ,task_address FROM SYS.DM_OS_SCHEDULERS OS INNER JOIN SYS.DM_OS_WORKERS OSW ON OS.scheduler_address=OSW.scheduler_address WHERE os.status='VISIBLE ONLINE' GROUP BY os.parent_node_id ,task_address ) node ON node.task_address=er.task_address LEFT JOIN (SELECT session_id, SUM(wait_duration_ms) AS wait_duration_ms,wait_type,blocking_session_id,COUNT(*) AS NoThread FROM SYS.DM_OS_WAITING_TASKS GROUP BY session_id, wait_type,blocking_session_id) wt ON wt.session_id=er.session_id CROSS apply SYS.DM_EXEC_SQL_TEXT(er.sql_handle) AS sqltxt WHERE sql_handle IS NOT NULL AND ISNULL(wt.wait_type ,'') NOT IN ('WAITFOR','BROKER_RECEIVE_WAITFOR') ORDER BY er.total_elapsed_time DESC GO
这里的输出列和第2步完全相同,我会分析total_elapsed_time占用时间较长的会话,酌情考虑是否终止这些会话,并分析下对应的执行SQL语句。大多数情况下(服务器一致运行稳定,突然卡住了),使用上述步骤就可以解决问题。下一篇文章我们会看下阻塞的会话,还有打开未活动事务的会话。
参考文章:
http://www.sqlservercentral.com/blogs/practicalsqldba/2012/09/21/sql-server-part-2-approaching-database-server-performance-issues/相关文章推荐
- oracle导出数据不全,可能是空表没有导出
- SQLServer代理作业以及邮件
- MySQL数据库使用命令行备份
- MongoDB设置访问权限、设置用户
- Memcached 缓存体系
- sql duplicate key
- 21分钟 MySQL 入门教程
- Teradata SQL programming
- UNDERSTANDING PSQL'S MVCC
- c#学习之-c#通过sql存储过程实现分页
- MySQL数据库高并发优化配置
- SQL中的左连接与右连接有什么区别,点解返回值会不同?(转)
- 查看mysql锁的详细信息
- ios 控制数据库的版本号
- mysql 配置 - on xFanxcy.com
- redis 学习的一些笔记
- 关于mysql的一个比较好的教程
- sqlite获取表信息
- MySQL备份导致的waiting for global read lock
- mysql数据库主从同步的问题解决方法