数据库教程22:SQL Server中如何查找查询慢、运行时间长的查询,sp_WhoIsActive及sp_WhoIsActive的替代

1,813 阅读3分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

下面主要探讨下,在SQL Server中如何查找查询慢的语句,也即运行时间长的SQL。通常功能比较全面、信息方便和灵活的就是使用sp_WhoIsActive,但由于其强大,因此也有一定的臃肿,在很多使用用不到那么多的特性,此时,通常可以考虑使用更轻量级地一些替代方案。以下部分,将对此进行一些简要介绍。

方法一:使用sp_WhoIsActive存储过程

sp_WhoIsActive可能是最出名的性能查找和故障排除的存储过程工具,由Adam Machanic开发提供。

其查询返回的第一列dd hh:mm:ss.mss,就是SQL语句执行的时间,由此可以查找运行时间长的会话。第二列则是session_id,即spid。

exec sp_WhoIsActive;

KILL spid; 中止会话session

方法二:使用sys.dm_exec_requests

sp_WhoIsActive功能强大,但相对也很笨重。由此可以直接从 sys.dm_exec_requests DMV中获取运行时间长会话

SELECT r.session_id,
       st.TEXT AS batch_text,
       qp.query_plan AS 'XML Plan',
       r.start_time,
       r.status,
       r.total_elapsed_time
FROM sys.dm_exec_requests AS r
     CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
     CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp
WHERE DB_NAME(r.database_id) = '{db_name}'
ORDER BY cpu_time DESC;

然后再执行kill命令

针对报表(report)长时间查询,导致应用查询使用慢的问题,这两者的情况可以考虑下面的建议:

  1. 报告(报表)和CRUD操作必须分开。至少可以使用 nolock (with (nolock)),或者晚上运行并且可以离线工作。
  2. 检查当前的查询,因为如果数据量小于2百万,则主要问题基本都是查询语句。
  3. 分析报告(报表)类型,如果适合离线工作,使用离线系统进行报告
  4. 可以使用镜像或其他技术进行报告。
  5. 最佳实践总是为报告和CRUD操作提供单独的数据库,即报表数据库和应用数据库分开。

sp_WhoIsActive的简单替代

有一些系统使用 sp_WhoIsActive 太慢了。这可能与资源相关,例如 CPU、内存或 TempDB 压力,或者是 DMV。

这时,你需要一个轻量级查询,它仍然可以获取用户提交的 SQL 文本,以及一些习惯常用的类似指标。

仅仅用到三个动态管理视图(DMV)

查看常用指标,只要这三个视图即可:dm_exec_requests, dm_exec_sessions 和 dm_exec_input_buffer。

SELECT s.session_id,
    r.start_time, 
    s.host_name, 
    s.login_name,
    i.event_info,
    r.status,
    s.program_name,
    r.writes,
    r.reads,
    r.logical_reads,
    r.blocking_session_id,
    r.wait_type,
    r.wait_time,
    r.wait_resource
FROM sys.dm_exec_requests as r
JOIN sys.dm_exec_sessions as s
 on s.session_id = r.session_id
CROSS APPLY sys.dm_exec_input_buffer(s.session_id, r.request_id) as i
WHERE s.session_id != @@SPID
and s.is_user_process = 1; -- 仅显示用户进程,如果想显示所有进程,去掉此条件即可。system processes

CROSS APPLY sys.dm_exec_sql_text(r.sql_handle)可以获取SQL文本,但是上面获取的i.event_info似乎也包含SQL语句。

  • sp_WhoIsActive结果的 sql_text 是确切的正在运行的SQL文本片段。

  • event_info 包含类似@PostType = 3的信息,它是用户提交到SQL Server的文字和整个文本。

关于sys.dm_exec_requests

  • sys.dm_exec_requests视图返回的是SQL Server中正在执行的每个请求的信息。也就是如果没有正在执行,是获取不到的。

  • sys.dm_exec_sessions 返回SQL Server上每个经过身份验证的会话,一个会话一行。 sys.dm_exec_sessions 是一个服务器范围的视图,显示所有活动用户连接和内部任务的信息。

参考