最大递归 32767 在语句完成之前已经用完。 [SQLSTATE 42000](错误 530)
The maximum recursion 32767 has been exhausted before statement completion. [SQLSTATE 42000] (Error 530)
我正在使用以下查询来识别服务器上的阻塞并发送警报同时终止会话(通过 SQL 作业执行)。
查询正在使用 2 CET table Blcokers 和 Hierarchy。
很多次我遇到错误并且作业失败。
错误:
新台币 SERVICE\SQLSERVERAGENT。声明终止。最大递归 32767 在语句完成之前已经用完。 [SQL状态 42000](错误 530)。该步骤失败。
在研究中我发现在查询中使用 OPTION(MAXRECURSION) HINT 来避免错误。
我已经包含了 HINT for Hierarchy CET table 如下所示,但仍然出现相同的错误
SELECT * INTO #BlockingProcess
从层次结构
选项(MAXRECURSION 32767)
有人可以建议我应该在下面的代码中进行哪些更改以停止无限递归。
编码:
SET nocount ON;
SET concat_null_yields_null OFF
go
CREATE TABLE #sp_who2(
ID INT IDENTITY(1,1) NOT NULL,
SPID VARCHAR(4),
Status VARCHAR(200),
Login VARCHAR(200),
HostName VARCHAR(200),
BlkBy VARCHAR(4),
DBName VARCHAR(200),
Command VARCHAR(200),
CPUTime VARCHAR(20),
DiskIO VARCHAR(20),
LastBatch VARCHAR(20),
ProgramName VARCHAR(200),
SPID2 VARCHAR(4),
RequestID VARCHAR(4)
)
INSERT #sp_who2
EXEC sp_who2
--SELECT SPID, BlkBy FROM #sp_who2
DELETE FROM #sp_who2
WHERE BlkBy=' .'
AND SPID NOT IN (SELECT BlkBy FROM #sp_who2 WHERE BlkBy IS NOT NULL)
;WITH Hierarchy(ChildSPID,Generation,BlkBy)
AS
(
SELECT SPID, 0, BlkBy
FROM #sp_who2 AS FirtGeneration
WHERE BlkBy=' .'
UNION ALL
SELECT NextGeneration.SPID, Parent.Generation+1, Parent.ChildSPID
FROM #sp_who2 AS NextGeneration
INNER JOIN Hierarchy AS Parent ON NextGeneration.BlkBy = Parent.ChildSPID
)
SELECT * INTO #BlockingProcess
FROM Hierarchy
OPTION(MAXRECURSION 32767)
SELECT * FROM #BlockingProcess
--loop and kill lead blockers
DECLARE @SPIDGen0 INT
DECLARE @SPIDGen1 INT
DECLARE @ElapsedTimeMSGen0 INT --if NULL, use Gen1
DECLARE @ElapsedTimeMSGen1 INT
DECLARE @SUBJECTKILL VARCHAR(200);
--DECLARE @tableHTMLKILL NVARCHAR(MAX);
WHILE EXISTS(SELECT * FROM #BlockingProcess WHERE BlkBy=' .')
BEGIN
SELECT @SPIDGen0=MIN(ChildSPID) FROM #BlockingProcess WHERE Generation=0
SELECT @SPIDGen1=MIN(ChildSPID) FROM #BlockingProcess WHERE Generation=1 and BlkBy=@SPIDGen0
PRINT @SPIDGen0
PRINT @SPIDGen1
SELECT @ElapsedTimeMSGen0 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @ElapsedTimeMSGen1 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen1
PRINT @ElapsedTimeMSGen0
PRINT @ElapsedTimeMSGen1
--If (select count(*) from #BLOCKERS) >= 1
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1) >= 120000
begin
DECLARE @Subject varchar(100)
SELECT @Subject = 'Blocking Tree Report from ' + @@servername
EXEC msdb.dbo.sp_send_dbmail @body = @tableHTML
,@body_format = 'HTML'
,@profile_name = N''
,@recipients = N''
,@Subject = @Subject
end
drop table #BLOCKERS
WAITFOR DELAY '00:03'
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>180000 --milliseconds = 3 minutes
--IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>60000 --milliseconds = 3 minutes
BEGIN
SELECT @SUBJECTKILL=@@SERVERNAME+' - Lead Blocker Session '+CAST(@SPIDGen0 AS VARCHAR(5))+' Killed'
EXEC msdb.dbo.sp_send_dbmail
@profile_name='',
@recipients='',
@subject = @SUBJECTKILL,
@body = @tableHTML,
@body_format = 'HTML'
EXEC('KILL ' + @SPIDGen0)
END
--Skip current SPID and move to next SPID
DELETE FROM #BlockingProcess WHERE ChildSPID = @SPIDGen0
END
IF OBJECT_ID('tempdb..#sp_who2') IS NOT NULL DROP TABLE #sp_who2
IF OBJECT_ID('tempdb..#BlockingProcess') IS NOT NULL DROP TABLE #BlockingProcess
改用sp_whoisactive。它可以很好地 human-readable 了解正在发生的事情以及正在处理或阻止其他进程的进程。
此外,您可以按 运行 时间过滤结果并杀死最慢的。
但是,你的做法似乎不对。您有用于终止交易的自动化脚本。如果每月生成一次发票报告需要 5 分钟,而您不断地取消它怎么办?如果一个人正在创建一个索引来阻止指定 table 上的事务并且你杀死它怎么办?
Microsoft 没有此类功能是有原因的 - 需要有人接听电话。
最好使用此例程来识别慢查询并修复它们。
我观察到,在上面的查询中,当并行会话阻塞自身时,它以某种方式超过了最大递归,不应将其视为阻塞。
因此,我通过在下面的删除语句中包含 OR SPID=BlkBy 来避免并行会话
DELETE FROM #sp_who2
WHERE BlkBy=' .'
AND SPID NOT IN (SELECT BlkBy FROM #sp_who2 WHERE BlkBy IS NOT NULL)
此后查询开始正常工作。
感谢您的回复。
抱歉回复晚了。
我已经删除了对 CET table 的依赖,因为当每个阻塞都是由于睡眠会话而我以前的脚本无法识别睡眠会话时进入最大递归。
我观察到 exec_requests dmv 没有捕获所有睡眠会话,因此一些脚本如何在睡眠会话阻塞时用于达到最大递归,因为我已经加入 exec_requests dmv 来获取阻塞数据。
解决方案:
我已将 CET 替换为 Temp Table,并将 exec_requests dmv 替换为 sys.sysprocesses 系统 table。这解决了最大递归问题。
此外,我还添加了一些过滤器来消除对睡眠会话的阻塞。
因此,现在查询会杀死 head blocker,如果它是一个活动会话并且阻塞超过 3 分钟,或者如果 head blocker 是一个休眠会话。
以下是修改后的完整查询,供您参考。肯定会有很多修改,如有建议请多多指教
SET nocount ON;
SET concat_null_yields_null OFF
go
WITH blockers (spid, blocked, level, batch, lastwaittype, status,hostname,cmd,DBNAME,loginname,open_tran,login_time)
AS (SELECT spid,
blocked,
Cast (Replicate ('0', 4-Len (Cast (spid AS VARCHAR)))
+ Cast (spid AS VARCHAR) AS VARCHAR (1000)) AS
LEVEL,
Replace (Replace (T.text, Char(10), ' '), Char (13), ' ') AS
BATCH,
R.lastwaittype,
R.status,
R.hostname,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses R WITH (nolock)
CROSS apply sys.Dm_exec_sql_text(R.sql_handle) T
WHERE ( blocked = 0
OR blocked = spid )
AND EXISTS (SELECT spid,
blocked,
Cast (Replicate ('0', 4-Len (Cast (spid AS
VARCHAR
)))
+ Cast (spid AS VARCHAR) AS VARCHAR (
1000))
AS
LEVEL,
blocked,
Replace (Replace (T.text, Char(10), ' '),
Char (13
),
' ') AS
BATCH,
R.lastwaittype,
R.status,
R.hostname,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses R2 WITH (nolock)
CROSS apply
sys.Dm_exec_sql_text(R.sql_handle) T
WHERE R2.blocked = R.spid
AND R2.blocked <> R2.spid
AND DB_NAME(r.dbid) NOT IN ('msdb'))
UNION ALL
SELECT R.spid,
R.blocked,
Cast (blockers.level
+ RIGHT (Cast ((1000 + R.spid) AS VARCHAR (100)), 4) AS
VARCHAR
(
1000)) AS
LEVEL,
Replace (Replace (T.text, Char(10), ' '), Char (13), ' ')
AS BATCH,
R.lastwaittype,
R.status,
R.hostname ,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses AS R WITH (nolock)
CROSS apply sys.Dm_exec_sql_text(R.sql_handle) T
INNER JOIN blockers
ON R.blocked = blockers.spid
WHERE R.blocked > 0
AND R.blocked <> R.spid
AND DB_NAME(r.dbid) NOT IN ('msdb'))
SELECT N''
+ Replicate (N'|.......', Len (level)/4 - 2)
+ CASE WHEN (Len (level)/4 - 1) = 0 THEN 'HEAD - ' ELSE '|------ ' END +
Cast (
spid AS VARCHAR (10)) + ' ' + batch AS BLOCKING_TREE,
Spid,
blocked,
hostname,
Status,
lastwaittype, cmd,DBNAME,loginname,open_tran,login_time,
Getdate() AS 'RunTime' ,
level
--(Select convert(varchar, total_elapsed_time /60000 ) + ':' + right('0' + convert(varchar(2), (total_elapsed_time /1000) % 60 ),2 ) from sys.dm_Exec_requests) as StartedSince
INTO #BLOCKERS
FROM blockers WITH (nolock)
ORDER BY level ASC
--select * from #BLOCKERS
DECLARE @tableHTML NVARCHAR(MAX);
SET @tableHTML = N'<H1>Blocking Tree Report</H1>' + N'<table border="1" bordercolor="#ff0000" cellspacing="0">' + N'<tr>' +
N'<th>Blocking_Tree</th>' + N'<th>hostname</th>' + N'<th>Status</th>' + N'<th>lastwaittype</th>'+'<th>CurrentTime</th>'
+ N'<th>cmd</th>'
+ N'<th>DatabaseName</th>'
+ N'<th>loginname</th>'
+ N'<th>open_tran</th>'
+ N'<th>login_time</th>'
+ '</tr>' + CAST((
SELECT td = Blocking_Tree,'',
td =hostname,'',
td =Status,'',
td =lastwaittype,'',
td =RunTime,'',
td= cmd,'',
td= DBNAME,'',
td= loginname,'',
td=open_tran,'',
td=login_time,''
FROM #BLOCKERS
order by level asc
FOR XML PATH('tr')
,TYPE
) AS NVARCHAR(MAX)) + N'</table>';
----------------------------------------------------------------
Insert Into [TOOLS].[dbo].[Lead_Blocker_Log]
select * from #BLOCKERS
------------------------------------------------------
SELECT * INTO #BlockingProcess
FROM #BLOCKERS
--select * from #BlockingProcess
---------------------------------------------------------
--loop and kill lead blockers
--DECLARE @SPIDGen2 INT
DECLARE @SPIDGen0 INT
DECLARE @SPIDGen1 INT
DECLARE @ElapsedTimeMSGen0 INT --if NULL, use Gen1
DECLARE @ElapsedTimeMSGen1 INT
DECLARE @SUBJECTKILL VARCHAR(200)
Declare @sleeping1 VARCHAR (50)
Declare @sleeping2 VARCHAR (50)
--DECLARE @tableHTMLKILL NVARCHAR(MAX);
IF EXISTS(SELECT * FROM #BlockingProcess WHERE Blocked NOt in ('0') )
Begin
SELECT @SPIDGen0=MIN(SPID) FROM #BlockingProcess WHERE Blocked=0
SELECT @SPIDGen1=MIN(SPID) FROM #BlockingProcess WHERE lastwaittype = 'LCK_M_U'
--PRINT @SPIDGen0
---PRINT @SPIDGen1
SELECT @ElapsedTimeMSGen0 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @ElapsedTimeMSGen1 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen1
--PRINT @ElapsedTimeMSGen0
--PRINT @ElapsedTimeMSGen1
SELECT @sleeping1 = BlockingRequest.status
FROM sys.dm_exec_sessions BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @sleeping2 = BlockingRequest.status
FROM sys.dm_exec_sessions BlockingRequest
WHERE session_id=@SPIDGen1
--PRINT @sleeping1
--PRINT @sleeping2
If (select count(*) from #BLOCKERS) > 1
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1) >180000 OR ISNULL (@sleeping1,@sleeping2) = 'sleeping'
begin
DECLARE @Subject varchar(100)
SELECT @Subject = 'Blocking Tree Report from ' + @@servername
EXEC msdb.dbo.sp_send_dbmail @body = @tableHTML
,@body_format = 'HTML'
,@profile_name = N'DBMailProfile'
,@Subject = @Subject
end
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>180000 OR ISNULL (@sleeping1,@sleeping2) = 'sleeping'--milliseconds = 3 minutes
--IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>60000 --milliseconds = 3 minutes
BEGIN
EXEC ('KILL ' + @SPIDGen0)
SELECT @SUBJECTKILL=@@SERVERNAME+' - Lead Blocker Session '+CAST(@SPIDGen0 AS VARCHAR(5))+' Killed'
EXEC msdb.dbo.sp_send_dbmail
@subject = @SUBJECTKILL,
@body = @tableHTML,
@body_format = 'HTML'
Print ('KILL ' + Convert (varchar (50),@SPIDGen0))
END
END
--IF OBJECT_ID('tempdb..#sp_who2') IS NOT NULL DROP TABLE #sp_who2
IF OBJECT_ID('tempdb..#BLOCKERS') IS NOT NULL DROP TABLE #BLOCKERS
IF OBJECT_ID('tempdb..#BlockingProcess') IS NOT NULL DROP TABLE #BlockingProcess
我正在使用以下查询来识别服务器上的阻塞并发送警报同时终止会话(通过 SQL 作业执行)。 查询正在使用 2 CET table Blcokers 和 Hierarchy。
很多次我遇到错误并且作业失败。
错误: 新台币 SERVICE\SQLSERVERAGENT。声明终止。最大递归 32767 在语句完成之前已经用完。 [SQL状态 42000](错误 530)。该步骤失败。
在研究中我发现在查询中使用 OPTION(MAXRECURSION) HINT 来避免错误。 我已经包含了 HINT for Hierarchy CET table 如下所示,但仍然出现相同的错误
SELECT * INTO #BlockingProcess 从层次结构 选项(MAXRECURSION 32767)
有人可以建议我应该在下面的代码中进行哪些更改以停止无限递归。
编码:
SET nocount ON;
SET concat_null_yields_null OFF
go
CREATE TABLE #sp_who2(
ID INT IDENTITY(1,1) NOT NULL,
SPID VARCHAR(4),
Status VARCHAR(200),
Login VARCHAR(200),
HostName VARCHAR(200),
BlkBy VARCHAR(4),
DBName VARCHAR(200),
Command VARCHAR(200),
CPUTime VARCHAR(20),
DiskIO VARCHAR(20),
LastBatch VARCHAR(20),
ProgramName VARCHAR(200),
SPID2 VARCHAR(4),
RequestID VARCHAR(4)
)
INSERT #sp_who2
EXEC sp_who2
--SELECT SPID, BlkBy FROM #sp_who2
DELETE FROM #sp_who2
WHERE BlkBy=' .'
AND SPID NOT IN (SELECT BlkBy FROM #sp_who2 WHERE BlkBy IS NOT NULL)
;WITH Hierarchy(ChildSPID,Generation,BlkBy)
AS
(
SELECT SPID, 0, BlkBy
FROM #sp_who2 AS FirtGeneration
WHERE BlkBy=' .'
UNION ALL
SELECT NextGeneration.SPID, Parent.Generation+1, Parent.ChildSPID
FROM #sp_who2 AS NextGeneration
INNER JOIN Hierarchy AS Parent ON NextGeneration.BlkBy = Parent.ChildSPID
)
SELECT * INTO #BlockingProcess
FROM Hierarchy
OPTION(MAXRECURSION 32767)
SELECT * FROM #BlockingProcess
--loop and kill lead blockers
DECLARE @SPIDGen0 INT
DECLARE @SPIDGen1 INT
DECLARE @ElapsedTimeMSGen0 INT --if NULL, use Gen1
DECLARE @ElapsedTimeMSGen1 INT
DECLARE @SUBJECTKILL VARCHAR(200);
--DECLARE @tableHTMLKILL NVARCHAR(MAX);
WHILE EXISTS(SELECT * FROM #BlockingProcess WHERE BlkBy=' .')
BEGIN
SELECT @SPIDGen0=MIN(ChildSPID) FROM #BlockingProcess WHERE Generation=0
SELECT @SPIDGen1=MIN(ChildSPID) FROM #BlockingProcess WHERE Generation=1 and BlkBy=@SPIDGen0
PRINT @SPIDGen0
PRINT @SPIDGen1
SELECT @ElapsedTimeMSGen0 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @ElapsedTimeMSGen1 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen1
PRINT @ElapsedTimeMSGen0
PRINT @ElapsedTimeMSGen1
--If (select count(*) from #BLOCKERS) >= 1
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1) >= 120000
begin
DECLARE @Subject varchar(100)
SELECT @Subject = 'Blocking Tree Report from ' + @@servername
EXEC msdb.dbo.sp_send_dbmail @body = @tableHTML
,@body_format = 'HTML'
,@profile_name = N''
,@recipients = N''
,@Subject = @Subject
end
drop table #BLOCKERS
WAITFOR DELAY '00:03'
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>180000 --milliseconds = 3 minutes
--IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>60000 --milliseconds = 3 minutes
BEGIN
SELECT @SUBJECTKILL=@@SERVERNAME+' - Lead Blocker Session '+CAST(@SPIDGen0 AS VARCHAR(5))+' Killed'
EXEC msdb.dbo.sp_send_dbmail
@profile_name='',
@recipients='',
@subject = @SUBJECTKILL,
@body = @tableHTML,
@body_format = 'HTML'
EXEC('KILL ' + @SPIDGen0)
END
--Skip current SPID and move to next SPID
DELETE FROM #BlockingProcess WHERE ChildSPID = @SPIDGen0
END
IF OBJECT_ID('tempdb..#sp_who2') IS NOT NULL DROP TABLE #sp_who2
IF OBJECT_ID('tempdb..#BlockingProcess') IS NOT NULL DROP TABLE #BlockingProcess
改用sp_whoisactive。它可以很好地 human-readable 了解正在发生的事情以及正在处理或阻止其他进程的进程。
此外,您可以按 运行 时间过滤结果并杀死最慢的。
但是,你的做法似乎不对。您有用于终止交易的自动化脚本。如果每月生成一次发票报告需要 5 分钟,而您不断地取消它怎么办?如果一个人正在创建一个索引来阻止指定 table 上的事务并且你杀死它怎么办?
Microsoft 没有此类功能是有原因的 - 需要有人接听电话。
最好使用此例程来识别慢查询并修复它们。
我观察到,在上面的查询中,当并行会话阻塞自身时,它以某种方式超过了最大递归,不应将其视为阻塞。
因此,我通过在下面的删除语句中包含 OR SPID=BlkBy 来避免并行会话
DELETE FROM #sp_who2
WHERE BlkBy=' .'
AND SPID NOT IN (SELECT BlkBy FROM #sp_who2 WHERE BlkBy IS NOT NULL)
此后查询开始正常工作。
感谢您的回复。
抱歉回复晚了。
我已经删除了对 CET table 的依赖,因为当每个阻塞都是由于睡眠会话而我以前的脚本无法识别睡眠会话时进入最大递归。 我观察到 exec_requests dmv 没有捕获所有睡眠会话,因此一些脚本如何在睡眠会话阻塞时用于达到最大递归,因为我已经加入 exec_requests dmv 来获取阻塞数据。
解决方案: 我已将 CET 替换为 Temp Table,并将 exec_requests dmv 替换为 sys.sysprocesses 系统 table。这解决了最大递归问题。
此外,我还添加了一些过滤器来消除对睡眠会话的阻塞。 因此,现在查询会杀死 head blocker,如果它是一个活动会话并且阻塞超过 3 分钟,或者如果 head blocker 是一个休眠会话。
以下是修改后的完整查询,供您参考。肯定会有很多修改,如有建议请多多指教
SET nocount ON;
SET concat_null_yields_null OFF
go
WITH blockers (spid, blocked, level, batch, lastwaittype, status,hostname,cmd,DBNAME,loginname,open_tran,login_time)
AS (SELECT spid,
blocked,
Cast (Replicate ('0', 4-Len (Cast (spid AS VARCHAR)))
+ Cast (spid AS VARCHAR) AS VARCHAR (1000)) AS
LEVEL,
Replace (Replace (T.text, Char(10), ' '), Char (13), ' ') AS
BATCH,
R.lastwaittype,
R.status,
R.hostname,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses R WITH (nolock)
CROSS apply sys.Dm_exec_sql_text(R.sql_handle) T
WHERE ( blocked = 0
OR blocked = spid )
AND EXISTS (SELECT spid,
blocked,
Cast (Replicate ('0', 4-Len (Cast (spid AS
VARCHAR
)))
+ Cast (spid AS VARCHAR) AS VARCHAR (
1000))
AS
LEVEL,
blocked,
Replace (Replace (T.text, Char(10), ' '),
Char (13
),
' ') AS
BATCH,
R.lastwaittype,
R.status,
R.hostname,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses R2 WITH (nolock)
CROSS apply
sys.Dm_exec_sql_text(R.sql_handle) T
WHERE R2.blocked = R.spid
AND R2.blocked <> R2.spid
AND DB_NAME(r.dbid) NOT IN ('msdb'))
UNION ALL
SELECT R.spid,
R.blocked,
Cast (blockers.level
+ RIGHT (Cast ((1000 + R.spid) AS VARCHAR (100)), 4) AS
VARCHAR
(
1000)) AS
LEVEL,
Replace (Replace (T.text, Char(10), ' '), Char (13), ' ')
AS BATCH,
R.lastwaittype,
R.status,
R.hostname ,r.cmd,DB_NAME(r.dbid),r.loginame,r.open_tran,r.login_time
FROM sys.sysprocesses AS R WITH (nolock)
CROSS apply sys.Dm_exec_sql_text(R.sql_handle) T
INNER JOIN blockers
ON R.blocked = blockers.spid
WHERE R.blocked > 0
AND R.blocked <> R.spid
AND DB_NAME(r.dbid) NOT IN ('msdb'))
SELECT N''
+ Replicate (N'|.......', Len (level)/4 - 2)
+ CASE WHEN (Len (level)/4 - 1) = 0 THEN 'HEAD - ' ELSE '|------ ' END +
Cast (
spid AS VARCHAR (10)) + ' ' + batch AS BLOCKING_TREE,
Spid,
blocked,
hostname,
Status,
lastwaittype, cmd,DBNAME,loginname,open_tran,login_time,
Getdate() AS 'RunTime' ,
level
--(Select convert(varchar, total_elapsed_time /60000 ) + ':' + right('0' + convert(varchar(2), (total_elapsed_time /1000) % 60 ),2 ) from sys.dm_Exec_requests) as StartedSince
INTO #BLOCKERS
FROM blockers WITH (nolock)
ORDER BY level ASC
--select * from #BLOCKERS
DECLARE @tableHTML NVARCHAR(MAX);
SET @tableHTML = N'<H1>Blocking Tree Report</H1>' + N'<table border="1" bordercolor="#ff0000" cellspacing="0">' + N'<tr>' +
N'<th>Blocking_Tree</th>' + N'<th>hostname</th>' + N'<th>Status</th>' + N'<th>lastwaittype</th>'+'<th>CurrentTime</th>'
+ N'<th>cmd</th>'
+ N'<th>DatabaseName</th>'
+ N'<th>loginname</th>'
+ N'<th>open_tran</th>'
+ N'<th>login_time</th>'
+ '</tr>' + CAST((
SELECT td = Blocking_Tree,'',
td =hostname,'',
td =Status,'',
td =lastwaittype,'',
td =RunTime,'',
td= cmd,'',
td= DBNAME,'',
td= loginname,'',
td=open_tran,'',
td=login_time,''
FROM #BLOCKERS
order by level asc
FOR XML PATH('tr')
,TYPE
) AS NVARCHAR(MAX)) + N'</table>';
----------------------------------------------------------------
Insert Into [TOOLS].[dbo].[Lead_Blocker_Log]
select * from #BLOCKERS
------------------------------------------------------
SELECT * INTO #BlockingProcess
FROM #BLOCKERS
--select * from #BlockingProcess
---------------------------------------------------------
--loop and kill lead blockers
--DECLARE @SPIDGen2 INT
DECLARE @SPIDGen0 INT
DECLARE @SPIDGen1 INT
DECLARE @ElapsedTimeMSGen0 INT --if NULL, use Gen1
DECLARE @ElapsedTimeMSGen1 INT
DECLARE @SUBJECTKILL VARCHAR(200)
Declare @sleeping1 VARCHAR (50)
Declare @sleeping2 VARCHAR (50)
--DECLARE @tableHTMLKILL NVARCHAR(MAX);
IF EXISTS(SELECT * FROM #BlockingProcess WHERE Blocked NOt in ('0') )
Begin
SELECT @SPIDGen0=MIN(SPID) FROM #BlockingProcess WHERE Blocked=0
SELECT @SPIDGen1=MIN(SPID) FROM #BlockingProcess WHERE lastwaittype = 'LCK_M_U'
--PRINT @SPIDGen0
---PRINT @SPIDGen1
SELECT @ElapsedTimeMSGen0 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @ElapsedTimeMSGen1 = BlockingRequest.total_elapsed_time
FROM sys.dm_exec_requests BlockingRequest
WHERE session_id=@SPIDGen1
--PRINT @ElapsedTimeMSGen0
--PRINT @ElapsedTimeMSGen1
SELECT @sleeping1 = BlockingRequest.status
FROM sys.dm_exec_sessions BlockingRequest
WHERE session_id=@SPIDGen0
SELECT @sleeping2 = BlockingRequest.status
FROM sys.dm_exec_sessions BlockingRequest
WHERE session_id=@SPIDGen1
--PRINT @sleeping1
--PRINT @sleeping2
If (select count(*) from #BLOCKERS) > 1
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1) >180000 OR ISNULL (@sleeping1,@sleeping2) = 'sleeping'
begin
DECLARE @Subject varchar(100)
SELECT @Subject = 'Blocking Tree Report from ' + @@servername
EXEC msdb.dbo.sp_send_dbmail @body = @tableHTML
,@body_format = 'HTML'
,@profile_name = N'DBMailProfile'
,@Subject = @Subject
end
IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>180000 OR ISNULL (@sleeping1,@sleeping2) = 'sleeping'--milliseconds = 3 minutes
--IF ISNULL(@ElapsedTimeMSGen0,@ElapsedTimeMSGen1)>60000 --milliseconds = 3 minutes
BEGIN
EXEC ('KILL ' + @SPIDGen0)
SELECT @SUBJECTKILL=@@SERVERNAME+' - Lead Blocker Session '+CAST(@SPIDGen0 AS VARCHAR(5))+' Killed'
EXEC msdb.dbo.sp_send_dbmail
@subject = @SUBJECTKILL,
@body = @tableHTML,
@body_format = 'HTML'
Print ('KILL ' + Convert (varchar (50),@SPIDGen0))
END
END
--IF OBJECT_ID('tempdb..#sp_who2') IS NOT NULL DROP TABLE #sp_who2
IF OBJECT_ID('tempdb..#BLOCKERS') IS NOT NULL DROP TABLE #BLOCKERS
IF OBJECT_ID('tempdb..#BlockingProcess') IS NOT NULL DROP TABLE #BlockingProcess