Hello all,
I have been attempting to create a procedure that will monitor a SQL server for block processes. if found I need it to log specific information about the process ie spid , blocking spid login time ect... but the main thing I need is the one thing that I am having trouble with, and that the SQL that was executed or executing. I am amazed that MS hasn't come up with a tool to do this.. but I digress.
The process that I am using seem to be pretty straight forward( its triggered by a scheduled job to run every 10 min). I check the sysprocesses table for any spids that are blocking ( but not blocking themselves) if found i dump all spids and detail into a temp table then loop through each spid that is blocking and attempt to grab the sql_handle (text) using the fn_get_sql() function. unfortunatly two things happen
1. When using the fn_get_sql() outside of the loop , and specifying a spid the results null ( reason... TRACE FLAG 2861) which turns out pretty much has NO documentation. From what I have found it looks like it enables SQL to store zero-cost procedures. Which would allow you to grab a once very volatile handle. in addtion it bloats you sysprocedurecache table and can lead to performance degration. (this of course is a huge issue)
2. And this may just be a coding thing but when the fn_get_sql() is used within then loop it returns the same execution( which it's usually it's self.)
Basically my question is does anyone have any ideas as how to track the SQL text that is executing or executed from a spid that is blocking.
BTW here is the code
Any thoughts?
Thanks
TalenX
I have been attempting to create a procedure that will monitor a SQL server for block processes. if found I need it to log specific information about the process ie spid , blocking spid login time ect... but the main thing I need is the one thing that I am having trouble with, and that the SQL that was executed or executing. I am amazed that MS hasn't come up with a tool to do this.. but I digress.
The process that I am using seem to be pretty straight forward( its triggered by a scheduled job to run every 10 min). I check the sysprocesses table for any spids that are blocking ( but not blocking themselves) if found i dump all spids and detail into a temp table then loop through each spid that is blocking and attempt to grab the sql_handle (text) using the fn_get_sql() function. unfortunatly two things happen
1. When using the fn_get_sql() outside of the loop , and specifying a spid the results null ( reason... TRACE FLAG 2861) which turns out pretty much has NO documentation. From what I have found it looks like it enables SQL to store zero-cost procedures. Which would allow you to grab a once very volatile handle. in addtion it bloats you sysprocedurecache table and can lead to performance degration. (this of course is a huge issue)
2. And this may just be a coding thing but when the fn_get_sql() is used within then loop it returns the same execution( which it's usually it's self.)
Basically my question is does anyone have any ideas as how to track the SQL text that is executing or executed from a spid that is blocking.
BTW here is the code
Code:
SET NOCOUNT ON
--check for orfan records if found flag the record as cleared ( seeing that the block has been removed.
IF EXISTS(SELECT SPID FROM DBAdmin.dbo.tProcessLog WITH (NOLOCK) WHERE CLEARED_FLAG = 0)
BEGIN
UPDATE a1
SET CLEARED_FLAG = 1, CLEARED_TIME = GETDATE() FROM master..SysProcesses a0
LEFT JOIN DBAdmin.dbo.tProcessLog a1
ON
a0.spid = a1.SPID and a0.blocked = a1.SPID_BLOCKING
WHERE a1.CLEARED_FLAG = 0 AND a0.SPID IS NULL
END
--check for blocks
IF EXISTS(SELECT SPID FROM master..SysProcesses WITH (NOLOCK)WHERE BLOCKED > 0)
--start process
BEGIN
--insert new log drop old temp and build spid list
DROP TABLE ##TEMPLOG001
SELECT SPID AS BLOCKED_BY , 0 AS USED INTO ##TEMPLOG001 FROM master..SysProcesses WITH (NOLOCK)
--flush through all blocking spids and return FULL SQL for each spid.
WHILE exists(SELECT BLOCKED_BY FROM ##TEMPLOG001 WHERE USED = 0)
BEGIN
DECLARE @BLOCKINGSPID AS INT
DECLARE @SPIDTSQL AS VARCHAR (8000)
SELECT TOP 1 @BLOCKINGSPID = BLOCKED_BY FROM ##TEMPLOG001 WHERE USED = 0
--get FULL sql from handle
DECLARE @Handle BINARY(20)
SELECT @Handle = sql_handle FROM master..SysProcesses WHERE SPID = @BLOCKINGSPID
--apply sql handle to var
SELECT @SPIDTSQL = text FROM ::fn_get_sql(@handle)
--update temp table to reflect used spid
UPDATE ##TEMPLOG001 SET USED = 1 WHERE BLOCKED_BY = @BLOCKINGSPID
--insert logging data
INSERT INTO DBAdmin.dbo.tProcessLog(SPID, SPID_BLOCKING, HOST_NAME, LOGIN_TIME, NUMBER_OF_THREADS, STATUS, ENTRY_TIME, WAIT_TYPE, WAIT_TIME, SQL_TEXT, CMD)
SELECT spid, blocked, hostname, login_time, COUNT(ecid), status, GETDATE(), waittype, waittime, @SPIDTSQL ,cmd
FROM MASTER..SysProcesses with (nolock)
WHERE SPID = @BLOCKINGSPID
GROUP BY spid, blocked, hostname, login_time, status, waittype, waittime, cmd
END
Any thoughts?
Thanks
TalenX