系统存储过程“sp_who”和“sp_who2”可以检讨实例上所有正在运行的进程,但它们缺少很多有助于性能监控和剖析过程的有用信息,也显示了很多如系统进程等无用的信息。
为此,Adam Machanic(自 2004 年起成为 Microsoft MVP)开拓了一个名为“sp_whoisactive”的更强大的存储过程,以补充 DBA 的实际需求与当前供应的过程(sp_who 和 sp_who2)之间的差距。
下面将会简要先容sp_who和sp_who2存储过程,及如何利用sp_whoisactive

官方先容,sp_who供应有关 Microsoft SQL Server 数据库引擎实例中当前用户、会话和进程的信息。可以过滤信息以仅返回那些非空闲、属于特定用户或属于特定会话的进程。
sp_who返回诸如会话进程ID (SPID-session process ID)、实行高下文ID (ECID-execution context ID)、进程状态(status)、壅塞会话ID(blk)、数据库名称(dbname)、与此进程关联的登录名(loginame)和主机名(hostname)以及命令类型(Cmd-command type)等信息。
blk为壅塞实行的会话ID
sp_Who2与sp_Who类似,但没有文档记录也没有支持,但它从当提高程返回更多信息和性能计数器,例如实行命令的程序名称(ProgramName)、磁盘IO(DiskIO-磁盘读写总次数)、CPU韶光(CPUTime-占用CPU运行的总韶光)、上次批处理实行韶光(LastBatch-末了一次调用存储过程或者实行查询的韶光)。
如截图所示,输出显示了包含不须要的所有正在运行的系统和用户进程,并且只能利用loginname和sessionid过滤结果。而实际可能须要隐蔽系统进程。
并且,以上输出不包含任何有关当前运行的SQL命令的信息,如开始实行韶光、实行持续韶光、等待信息等。
sp_Who和sp_Who2返回活动的、某个用户或SPID的进程信息返回某个用户的进程信息如下,返回sa用户的会话进程信息
exec sp_who 'sa';-- exec sp_who2 'sa';-- exec sp_who @loginame='sa';
exec sp_who 'ACTIVE';-- EXEC sp_who2 'active';
exec sp_who2 '1';exec sp_who2 1;-- exec sp_who '1';-- exec sp_who 1;
如下,有个示例可以保存sp_Who2的结果到表或表变量或临时表中。用于过滤显示
DECLARE @Table TABLE( SPID INT, Status VARCHAR(MAX), LOGIN VARCHAR(MAX), HostName VARCHAR(MAX), BlkBy VARCHAR(MAX), DBName VARCHAR(MAX), Command VARCHAR(MAX), CPUTime INT, DiskIO INT, LastBatch VARCHAR(MAX), ProgramName VARCHAR(MAX), SPID_1 INT, REQUESTID INT)INSERT INTO @Table EXEC sp_who2SELECT FROM @TableWHERE ....
借助sysprocesses获取类似信息:
SELECT spid, sp.[status], loginame [Login], hostname, blocked BlkBy, sd.name DBName, cmd Command, cpu CPUTime, physical_io DiskIO, last_batch LastBatch, [program_name] ProgramName FROM master.dbo.sysprocesses sp JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid ORDER BY spid
下载安装whoisactive存储过程可以直接从whoisactive下载页下载该存储过程,或者GitHub repository。
最新版是2018发布的,适用于SQL Server2005+所有的版本。
下载后解压缩,并打开who_is_active.sql文件,在SSMS中实行(who_is_active_v11_32.sql)
利用sp_Whoisactiveexec sp_Whoisactive;
实行后,可以看到,默认仅返回正在运行的用户进程,并供应每个进程下面的信息:
sp_Whoisactive信息和sp_who、sp_who2比拟:
Column
Description
Shown by sp_who
Shown by sp_who2
dd hh:mm:ss.mss
Process elapsed time
No
No
session_id
The process session id
Yes
Yes
sql_text
The currently running SQL command
No
No
login_name
The login name associated with the process
Yes
Yes
wait_info
The process wait information (aggregated)
No
Yes(实际彷佛没有)
CPU
The CPU time
No
Yes
tempdb_allocations
Number of Tempdb writes done
No
No
tempdb_current
Number of Tempdb pages currently allocated
No
No
blocking_session_id
The blocking session Id
Yes
Yes
reads
number of reads done
No
Disk IO
writes
number of writes done
No
Disk IO
physical reads
number of physical reads done
No
Disk IO
used_memory
the amount of memory used
No
No
status
The process status
Yes
Yes
open_tran_count
the number of transactions used
No
No
percent_complete
the query completion percentage
No
No
host_name
The host machine name
Yes
Yes
database_name
The database name where the query is executed
Yes
Yes
program_name
The application that executed the query
No
Yes
start_time
The process start time
No
Yes
login_time
The login time
No
No
request_id
The request Id
Yes
Yes
collection_time
The time that this last select was run
No
No
sp_Whoisactive输出列信息的先容上面的比拟已经对列进行了简要的先容,下面再多做些解释。
dd hh:mm:ss:mss:显示命令的持续韶光(实行韶光)。可以利用此列来识别永劫光运行的事务。例如,可以识别运行韶光超过 1 小时的 SQL Server 会话。 它显示一个活动要求的查询运行韶光。 在就寝会话(sleeping session)的情形下,它显示自上次完成批以来的韶光session_id:用户会话的 SP ID。Sql_text:正在运行的会话的SQL文本。它是一个超链接,点击它并得到完全的t-SQL。Login name:是连接到SQL Server并实行会话中指定的SQL的登录名Wait_info:它是一个有用的列,用于识别 SPID 确当前等待,例如 CXPACKET、ASYNC_NETWORK_IO 以及等待韶光。请参阅有关 SQL Server等待类型的文章。Tempdb_allocations 和 tempdb_current:如果查询正在利用 TempDB 数据库,可以利用此列获取有关 tempdb 分配的信息。例如,如果我们利用一个表变量或临时表,它会在 TempDB 中创建,我们可以利用这两个列来跟踪信息。CPU:从中得到查询花费的总 CPU 韶光。Blocking_session_id:在壅塞的情形下,可以从这个列中获取壅塞的session-id。Reads和writes:给出当前查询的读写次数。Open_tran_count:当前会话打开的事务数。Percent complete:常日可以利用DMV sys.dm_exec_requests 检讨少数命令完成状态的百分比,例如备份和规复数据库命令。Sp_WhoIsActive利用该DMV信息并将其显示输出。Program name:给出了用户连接的运用程序名称,例如 Microsoft SQL Server Management Studio – Query、Azure Data Studio、SQL Server Agent 等。更多的详细参数先容推举查看SQL Server - Using SP WhoIsActive to identify Locks, Blocks, Slow Queries, Running Queries, and more中的先容
sp_whoisactive显示系统进程Exec sp_whoisactive @show_system_spids = 1;
还可以利用@get_additional_info、@get_locks、@get_avg_time等参数查看更多信息。
sp_Whoisactive的@help参数sp_whoisactive比较吸引人的一个功能是@help参数。所有干系信息都可以通过实行以下命令得到:
Exec sp_whoisactive @help = 1;
help命令包含三个部分:
一样平常信息:供应版本、版权、网站、反馈邮箱、URL等一样平常信息参数解释:个中供应了所有可用参数及其解释和默认信息的列表输出列描述:所有可用输出列的完全列表及其描述sp_WhoIsActive过程的几个可选参数和用法@find_block_leaders查看导致壅塞和被壅塞的会话可以将 @find_block_leaders 参数的值设置为 1 并对 blocks_session_count 列的结果进行排序,用以检讨导致壅塞和被壅塞的会话-sessions。
EXEC sp_WhoIsActive @find_block_leaders = 1, @sort_order = '[blocked_session_count] DESC';
从输出结果可以看到,session_id为55的会话导致了壅塞,后面是它壅塞的2个会话
@get_plans获取正在查询的实行操持
假设我们正在调查 SQL Server 中的性能问题,并且创造了有问题的查询。如果能得到对应的实行操持来查看查询实行中涉及的本钱高的操作,那就太好了。
此时,可以指定参数@get_plans=1,它会在输出中附加一个带 XML 实行操持的列。
EXEC sp_WhoIsActive @get_plans = 1;
query_plan列输出实行操持,必须为当前正在实行的查询语句。如果已经实行完,或没有正在实行的SQL语句,将会返回NULL
点击查询操持(query_plan),可以看到该查询的实行操持。
@get_locks获取详细的锁信息
可以利用这个参数来获取一个 XML 片段,里面是有关 SQL Server 会话中持有的锁的详细信息。在输出中,会多出一个额外的locks列。如下所示,单击locks,将看到 XML 格式的详细锁信息。
EXEC sp_WhoIsActive @get_locks = 1;
我们可以设置几个可能影响查询性能的会话参数。 Sp_WhoIsActive供应的参数 @get_additional_info ,会显示有关这些参数的信息。同样会额外输出一列,列为additional_info。
EXEC sp_WhoIsActive @get_additional_info = 1;
sp_WhoIsActive供应了它的结果表的创建脚本,直策应用输出参数@schema即可得到。
declare @HistTableName VARCHAR(MAX)= 'HistWhoIsActive';declare @schema VARCHAR(MAX);EXEC sp_WhoIsActive @get_transaction_info = 1, @get_outer_command = 1, @get_plans = 1, @return_schema = 1, @schema = @schema OUTPUT;-- 输出<table_name>占位组成的创建表的脚本select @schema;-- 天生创建表的脚本并实行创建EXEC (REPLACE(@schema, '<table_name>', @destination_table));
如果想要定期保存正在运行的进程信息以供进一步剖析,则可以将sp_whoisactive放在代理作业中实行保存到表中。
创建一个新job并将以下代码放入作业步骤(job step·),根据须要修正前3个变量。如果不存在,代码将创建日志记录表,如果不存在则创建聚拢索引,记录当前的活动并根据@retention变量打消旧数据。
该当多久网络一次活动?原作者认为每30-60秒网络一次 sp_WhoIsActive 数据,这是一个在记录足够的活动以办理生产问题和非常繁忙的环境中保持所需的数据存储之间的良好平衡。
如下,也可以将其改为一个存储过程来处理:
SET NOCOUNT ON;DECLARE @retention INT = 7, @destination_table VARCHAR(500) = 'WhoIsActive', @destination_database sysname = 'Crap', @schema VARCHAR(MAX), @SQL NVARCHAR(4000), @parameters NVARCHAR(500), @exists BIT;SET @destination_table = @destination_database + '.dbo.' + @destination_table;--create the logging tableIF OBJECT_ID(@destination_table) IS NULL BEGIN; EXEC dbo.sp_WhoIsActive @get_transaction_info = 1, @get_outer_command = 1, @get_plans = 1, @return_schema = 1, @schema = @schema OUTPUT; SET @schema = REPLACE(@schema, '<table_name>', @destination_table); EXEC ( @schema ); END;--create index on collection_timeSET @SQL = 'USE ' + QUOTENAME(@destination_database) + '; IF NOT EXISTS (SELECT FROM sys.indexes WHERE object_id = OBJECT_ID(@destination_table) AND name = N''cx_collection_time'') SET @exists = 0';SET @parameters = N'@destination_table varchar(500), @exists bit OUTPUT';EXEC sys.sp_executesql @SQL, @parameters, @destination_table = @destination_table, @exists = @exists OUTPUT;IF @exists = 0 BEGIN; SET @SQL = 'CREATE CLUSTERED INDEX cx_collection_time ON ' + @destination_table + '(collection_time ASC)'; EXEC ( @SQL ); END;--collect activity into logging tableEXEC dbo.sp_WhoIsActive @get_transaction_info = 1, @get_outer_command = 1, @get_plans = 1, @destination_table = @destination_table;--purge older dataSET @SQL = 'DELETE FROM ' + @destination_table + ' WHERE collection_time < DATEADD(day, -' + CAST(@retention AS VARCHAR(10)) + ', GETDATE());';EXEC ( @SQL );
网络sp_whoisactive的信息记录,也可以利用Insert Into命令,Insert Into <hist_table_name> Exec sp_whoisactive;。仍旧推举上面的方法。
如何查询sp_whoisactive的结果下面只是一个入门查询。可以根据早些时候用户抱怨查询非常缓慢,来查看特定时间段的信息。比如,我(原作者)曾经利用 WhoIsActive 日志表来确定是谁导致 tempdb 变得非常大。当我找到它时,tempdb 的大小为 500GB!
我将查询切换为包括 tempdb_allocations 和 tempdb_current 以及 ORDER BY tempdb_allocations DESC,这样就会很明显知道业务用户正在查询的所有事情。
SELECT TOP 1000 CPU, reads, collection_time, start_time, [dd hh:mm:ss.mss] AS 'run duration', [program_name], login_name, database_name, session_id, blocking_session_id, wait_info, sql_text, FROM WhoIsActiveWHERE collection_time BETWEEN '2016-07-20 07:55:00.000' AND '2016-07-20 09:00:00.000'AND login_name NOT IN ('DomainName\sqlservice')--AND CAST(sql_text AS varchar(max)) LIKE '%some query%'ORDER BY 1 DESC
如何利用 sp_WhoIsActive 查找 SQL Server 慢查询
本部分建议直接参考How to Use sp_WhoIsActive to Find Slow SQL Server Queries原文。原文供应了脚本工具下载(下载的脚本有些长,可能无法先容...),且有一个视频教程(需qiang)
DBA须要可以快速找到哪个查询和存储过程运行得比较慢。
sp_WhoIsActive有各种参数,但要知道,传入的参数越多,sp_WhoIsActive须要做的事情就越多,以便从 SQL Server 的动态管理视图 (DMV) 中获取想要的数据,运行速率也会越慢。
下面是几个很有用的参数:
@get_plans = 1 – 供应运行查询的实行操持。@get_locks = 1 – 供应一个 XML 片段,可以单击以查看每个查询拥有哪些表、行、工具等锁。当试图找出某个查询阻挡其他查询实行的缘故原由时很有用。@get_task_info = 2 – 如果一个查询并行进行,且你正在对 CXPACKET等待 (CXPACKET waits)进行故障打消,则可以找出查询中的每个任务正在等待什么。