A Better sp_who2 using DMVs (sp_who3)
-
Posted on June 19, 2009 by Derek Dieter
-
5
The following code generates the same information found in sp_who2, along with some additional troubleshooting information. It also contains the SQL Statement being run, so instead of having to execute a separate DBCC INPUTBUFFER, the statement being executed is shown in the results.
Unlike sp_who2, this custom sp_who3 only shows sessions that have a current executing request.
What is also shown is the reads and writes for the current command, along with the number of reads and writes for the entire SPID. It also shows the protocol being used (TCP, NamedPipes, or Shared Memory).
The lead blocker below will show in the BlkBy column as -1.
[cc lang=”sql”]
USE [master]
GO
CREATE PROCEDURE [dbo].[sp_who3]
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT
SPID = er.session_id
,BlkBy = CASE WHEN lead_blocker = 1 THEN -1 ELSE er.blocking_session_id END
,ElapsedMS = er.total_elapsed_time
,CPU = er.cpu_time
,IOReads = er.logical_reads + er.reads
,IOWrites = er.writes
,Executions = ec.execution_count
,CommandType = er.command
,LastWaitType = er.last_wait_type
,ObjectName = OBJECT_SCHEMA_NAME(qt.objectid,dbid) + ‘.’ + OBJECT_NAME(qt.objectid, qt.dbid)
,SQLStatement =
SUBSTRING
(
qt.text,
er.statement_start_offset/2,
CASE WHEN
(
CASE WHEN er.statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(MAX), qt.text)) * 2
ELSE er.statement_end_offset
END – er.statement_start_offset / 2
) < 0 THEN 0
ELSE
CASE WHEN er.statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(MAX), qt.text)) * 2
ELSE er.statement_end_offset
END - er.statement_start_offset / 2
END
)
,STATUS = ses.STATUS
,[Login] = ses.login_name
,Host = ses.host_name
,DBName = DB_Name(er.database_id)
,StartTime = er.start_time
,Protocol = con.net_transport
,transaction_isolation =
CASE ses.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END
,ConnectionWrites = con.num_writes
,ConnectionReads = con.num_reads
,ClientAddress = con.client_net_address
,Authentication = con.auth_scheme
,DatetimeSnapshot = GETDATE()
,plan_handle = er.plan_handle
FROM sys.dm_exec_requests er
LEFT JOIN sys.dm_exec_sessions ses
ON ses.session_id = er.session_id
LEFT JOIN sys.dm_exec_connections con
ON con.session_id = ses.session_id
OUTER APPLY sys.dm_exec_sql_text(er.sql_handle) AS qt
OUTER APPLY
(
SELECT execution_count = MAX(cp.usecounts)
FROM sys.dm_exec_cached_plans cp
WHERE cp.plan_handle = er.plan_handle
) ec
OUTER APPLY
(
SELECT
lead_blocker = 1
FROM master.dbo.sysprocesses sp
WHERE sp.spid IN (SELECT blocked FROM master.dbo.sysprocesses WITH (NOLOCK) WHERE blocked != 0)
AND sp.blocked = 0
AND sp.spid = er.session_id
) lb
WHERE er.sql_handle IS NOT NULL
AND er.session_id != @@SPID
ORDER BY
CASE WHEN lb.lead_blocker = 1 THEN -1 * 1000 ELSE -er.blocking_session_id END,
er.blocking_session_id DESC,
er.logical_reads + er.reads DESC,
er.session_id;
END
[/cc]
- Comments (RSS)
- Trackback
- Permalink
Used this today to track down an Access DB that was locking up a table. Having the SQL statement and IP address was very helpful. Thanks!
Watch out for the < in the above code for the SQLStatement.
It should be <
CASE WHEN er.statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(MAX), qt.text)) * 2
ELSE er.statement_end_offset
END – er.statement_start_offset / 2 < 0
Is there any value in using sys.sysprocesses instead of master.dbo.sysprocesses ?
Since sys.proccesses doesn’t exist in SQL AZURE, I had to come up with some changes for it to work.
ALTER PROCEDURE [dbo].[Sp_who3]
AS
BEGIN
SET TRANSACTION isolation level READ uncommitted
SELECT SPID = er.session_id,
–,BlkBy = CASE WHEN lead_blocker = 1 THEN -1 ELSE er.blocking_session_id END,
ElapsedMS = er.total_elapsed_time,
CPU = er.cpu_time,
IOReads = er.logical_reads + er.reads,
IOWrites = er.writes,
Executions = ec.execution_count,
CommandType = er.command,
LastWaitType = er.last_wait_type,
ObjectName = Object_schema_name(qt.objectid, dbid) + ‘.’
+ Object_name(qt.objectid, qt.dbid),
SQLStatement = Substring (qt.text, er.statement_start_offset / 2, (
CASE
WHEN
er.statement_end_offset = -1 THEN
Len
(
CONVERT(NVARCHAR(max), qt.text)) *
2
ELSE
er.statement_end_offset
END –
er.statement_start_offset ) / 2),
STATUS = ses.status,
[Login] = ses.login_name,
Host = ses.host_name,
DBName = Db_name(er.database_id),
StartTime = er.start_time,
Protocol = con.net_transport,
transaction_isolation = CASE ses.transaction_isolation_level
WHEN 0 THEN ‘Unspecified’
WHEN 1 THEN ‘Read Uncommitted’
WHEN 2 THEN ‘Read Committed’
WHEN 3 THEN ‘Repeatable’
WHEN 4 THEN ‘Serializable’
WHEN 5 THEN ‘Snapshot’
END,
ConnectionWrites = con.num_writes,
ConnectionReads = con.num_reads,
ClientAddress = con.client_net_address,
Authentication = con.auth_scheme,
DatetimeSnapshot = Getdate(),
plan_handle = er.plan_handle
FROM sys.dm_exec_requests er
LEFT JOIN sys.dm_exec_sessions ses
ON ses.session_id = er.session_id
LEFT JOIN sys.dm_exec_connections con
ON con.session_id = ses.session_id
OUTER apply sys.Dm_exec_sql_text(er.sql_handle) AS qt
OUTER APPLY
(
SELECT execution_count = MAX(cp.usecounts)
FROM sys.dm_exec_cached_plans cp
WHERE cp.plan_handle = er.plan_handle
) ec
/*OUTER APPLY
(
SELECT
lead_blocker = 1
FROM master.dbo.sysprocesses sp
WHERE sp.spid IN (SELECT blocked FROM master.dbo.sysprocesses)
AND sp.blocked = 0
AND sp.spid = er.session_id
) lb*/
WHERE er.sql_handle IS NOT NULL
AND er.session_id != @@SPID
ORDER BY
–CASE WHEN lead_blocker = 1 THEN -1 * 1000 ELSE -er.blocking_session_id END,
er.blocking_session_id DESC,
er.logical_reads + er.reads DESC,
er.session_id
END
When I run the query these messages appears:Msg 102, Level 15, State 1, Procedure sp_who3, Line 54
Incorrect syntax near ‘.’.
Msg 102, Level 15, State 1, Procedure sp_who3, Line 60
Incorrect syntax near ‘ec’.
Msg 102, Level 15, State 1, Procedure sp_who3, Line 69
Incorrect syntax near ‘lb’.
Please help, thanks in advance.
This has worked awesomely the past few weeks, but today the results I get show this SPID (sp_who3) as the top (-1) blocker, and I am unable to run anything. How is this possible, and how to I solve it? Has anyone seen this before?
This is awesome. i made one small change that others may find useful. Preceding the order by statement, I added the following where clause line to filter out the spwo3 process. change the name of the process, dbo.sp_who3 in this case, to whatever yours shows up as. This varies depending on where you placed the stored procedure.
where qt.objectid OBJECT_ID(‘dbo.sp_who3’)
ORDER BY
er.blocking_session_id DESC,
er.logical_reads + er.reads DESC,
er.session_id
END
This worked like a Charm Derek.. I was able to pinpoint the offender really quick and nip it in the bud.
Nice work but it only seems to find connections to the master,tempdb databases…
EXEC SP_WHO2 gives me about 100 result and your query only 20…
Hi Peter,
This is because this script only shows active connections. Personally I prefer this because when troubleshooting, I can immediately see how busy the server is just by the sheer number of results. sp_who2 will show all connections and I need to figure out which ones are asleep. To change this to show sleeping connections, simply join the sessions table first, then left join on the dm_exec_requests
Derek
Nice. I have a long running Select (over 50 minutes). I’m running sp_who3 with sp_who2 in the same window. who2 DiskIO column is increasing each time I rerun, but who3 IOReads and IOWrites are static at the same values as the first time I ran it in this SSMS window. I would have expected who3 to change. I can see who3 changing ElapsedMS. CPUTime looks frozen too. Is this behaving as intended? Thanks for the tool!
It is ok in sql 2008 but can not save in sql 2000, got an error:
Incorrect syntax near the keyword ‘OUTER’.
(OUTER APPLY sys.dm_exec_sql_text(er.sql_handle) st)
Excellent example, this is a big help for me in our monitoring application.
[…] fix. It is likely you have a run away query. The first thing you want to do is run sp_who2 (or sp_who3) and look for connections that have a SPID > 50 with abnormally high CPU time. The CPU time shown […]