什么时候执行计划不显示在 sp_WhoIsActive 中?

Som*_*Guy 9 performance sql-server stored-procedures execution-plan sp-whoisactive query-performance

我使用 Adam Machanic 的出色sp_WhoIsActive过程来查看活动并记录到表中以对长时间运行的查询进行故障排除。

为什么执行计划没有一直显示在结果中?大多数情况下,该query_plan值为 NULL。如果我查看结果中的SQL_TEXT列,我会看到带有参数但没有值的查询,如下所示:

(@P0 nvarchar(4000),@P1 nvarchar(4000))
select blah from foo where a = @P0 and b = @P1 
Run Code Online (Sandbox Code Playgroud)

执行计划未显示在此处时如何获取它们?他们为什么不显示?我必须使用 Profiler 或扩展事件吗?将虚拟值放入这些参数并运行包含实际执行计划的查询是否会生成与我记录时实际使用的计划相同的计划?

我已经与供应商确认他们正在使用 Hibernate 3.5。

Geo*_*son 12

执行计划未显示在此处时如何获取它们?

一种选择可能是捕获plan_handle,然后plan_handle使用以下查询查找查询计划:

SELECT CONVERT(XML, query_plan) from sys.dm_exec_text_query_plan(
    0x0600050059E32C0/*Truncated for brevity, replace with your full plan_handle*/,
    DEFAULT,
    DEFAULT
)
Run Code Online (Sandbox Code Playgroud)

您可以plan_handle使用Reason #1下面部分中的查询来捕获 ,或者您可以进行小的编辑以sp_whoisactive在结果中显示它。(它已在 中使用的中间#sessions表中捕获sp_whoisactive)。

在我观察到NULL查询计划的每种情况下,查询计划很快就可以通过这种方法使用(在我的所有情况下都小于 1 秒)。

将虚拟值放入这些参数并运行包含实际执行计划的查询是否会生成与我记录时实际使用的计划相同的计划?

这可以让您了解计划可能是什么样子,如果RetrievedFromCache查询计划的属性是true,您很可能会看到正在使用的相同计划。

为什么查询计划不显示在 sp_whoisactive 中?

至少有几个可能的原因导致计划可能不会出现,但我没有以与您报告的频率相同的频率观察到这一点,并且看到任何其他填补空白的答案会很有趣。

原因 #1:sys.dm_exec_requests 报告 statement_start_offset 为 -1

首先,让我们看一下sp_whoisactive查找查询计划部分的简化版本:

SELECT t.text,
    r.plan_handle,
    r.statement_start_offset,
    r.statement_end_offset,
    query_plan = (
        SELECT CONVERT(xml, query_plan)
        FROM sys.dm_exec_text_query_plan (
            r.plan_handle, 
            r.statement_start_offset,
            r.statement_end_offset
        )
    )
FROM sys.dm_exec_sessions s
JOIN sys.dm_exec_requests r
    ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.is_user_process = 1
Run Code Online (Sandbox Code Playgroud)

这是来自我的服务器的示例结果:

在此处输入图片说明

根据文档,-1 似乎不是sys.dm_exec_requests.statement_start_offset. 但它似乎确实有些频繁地出现,并且该sp_whoisactive程序并未尝试处理这种情况。

在我的测试中,我什至不确定是否有可能这样做;即使sys.dm_exec_text_query_plan使用默认值调用(查找整个计划,而不是基于偏移量的特定计划),我发现当sys.dm_exec_requests.statement_start_offset为 -1时没有提供任何计划。

我认为存在请求存在但计划和当前语句偏移量尚不可用的情况的可能性。我不知道这种行为的完整解释。由于 aplan_handle可用(至少在我有NULL计划的情况下),我不认为计划编译仍在发生。

原因#2:查找查询计划耗时超过5ms

的完整实现sp_whoisactive实际上使用游标一次查找每个计划。有一个LOCK_TIMEOUTof5ms可以避免在查找特定计划时遇到锁定而过多地延迟整个过程。

--Wait up to 5 ms for the SQL text, then give up
SET LOCK_TIMEOUT 5;
WHILE @@FETCH_STATUS = 0
...
Run Code Online (Sandbox Code Playgroud)

但是,在这种情况下,输出sp_whoisactive应该显示<timeout_exceeded />query_plan字段中。我已经看过几次了,所以我认为NULL在您的情况下,值更有可能是原因#1。

原因 #3:查询计划 XML 太复杂

如果查询文本与您的示例一样简单,这在您的情况下似乎不太可能。然而,它看起来像还有的可能性,一个NULL查询计划正在显示由于XML是太复杂了。

但是,通过查看sp_whoisactive,看起来这种情况是使用消息Could not render showplan due to XML data type limitations.和指令处理的,将原始 XML 转换为 .sqlplan 文件。