带函数调用的估计查询计划与实际查询计划


11

我在SQL Server上有此查询,这是一个合并复制查询:

SELECT DISTINCT
    b.tablenick,
    b.rowguid,
    c.generation,
    sys.fn_MSgeneration_downloadonly
    (
        c.generation,
        c.tablenick
    )
FROM #belong b
LEFT OUTER JOIN dbo.MSmerge_contents c ON 
    c.tablenick = b.tablenick
    AND c.rowguid = b.rowguid;

估计的查询计划包括有关3个查询的信息:

  1. 上面的查询
  2. 函数调用fn_MSgeneration_downloadonly
  3. 对fn_MSArticle_has_downloadonly_property的函数调用

实际的查询计划仅包含以下信息:

  1. 上面的查询

与功能无关。为什么实际计划中缺少功能信息?

我尝试了以下选项:

SET STATISTICS PROFILE ON
SET STATISTICS XML ON

它创建了一个实际计划,但缺少第2部分和第3部分,与我在Management Studio中使用实际查询计划选项时相同。

例如,如果我要使用Profiler捕获有关函数调用的信息,我将选择哪些事件?


找不到与查询计划特别相关的答案,但我分析了SP:StmtStarting和SP:StmtCompleted并显示了函数调用。

Answers:


17

与功能无关。为什么实际计划中缺少功能信息?

出于性能原因,这是设计使然。

包含BEGINEND定义中的函数为每个输入行创建一个新的T-SQL堆栈框架。换句话说,对每个输入行单独执行函数体。这个事实说明了与T-SQL标量和多语句函数相关的大多数性能问题(请注意,内联表值函数不使用BEGIN...END语法)。

就您的问题而言,这将导致SHOWPLAN每一行的完整输出。XML计划输出非常冗长且生产成本高昂,因此一般而言,为每一行产生完整输出将是一个坏主意。

考虑下面在AdventureWorks示例数据库中创建的T-SQL标量函数,该函数以给定ID的形式返回产品名称:

CREATE FUNCTION dbo.DumbNameLookup
(
    @ProductID integer
)
RETURNS dbo.Name
AS
BEGIN
    RETURN
    (
        SELECT
            p.Name
        FROM Production.Product AS p
        WHERE
            p.ProductID = @ProductID
    );
END;

执行前计划

执行前计划(SSMS中的估计计划)显示父语句和嵌套函数调用的计划信息:

-- Pre-execution plan shows main query and nested function call
SET SHOWPLAN_XML ON;
GO
SELECT dbo.DumbNameLookup(1);
GO
SET SHOWPLAN_XML OFF;

SSMS输出:

SSMS执行前计划

SQL Sentry Plan Explorer中查看的相同XML 更清楚地显示了调用的嵌套性质:

PE预执行计划

执行后输出

当请求执行后计划输出时,SSMS仅显示主要查询的详细信息:

-- Post-execution plan shows main query only
SET STATISTICS XML ON;
SELECT dbo.DumbNameLookup(1);
SET STATISTICS XML OFF;

SSMS执行后

可以使用SQL Server Profiler中的Showplan XML Statistics Profile事件类,使用多次调用该函数的查询(每个输入行一次)来显示这样做的性能影响。

SELECT TOP (5)
    p.ProductID,
    dbo.DumbNameLookup(p.ProductID)
FROM Production.Product AS p;

探查器输出:

跟踪输出

对于函数执行,有五个单独的执行后计划,对于父查询有一个。这五个功能计划在事件探查器下部窗格中如下所示:

功能计划

父查询计划为:

家长计划

在不使用该TOP (5)子句的情况下执行查询将为Product表中的504行的每一个制定完整的执行计划。您可能会发现,使用较大的表会很快变得不合时宜。

触发器的情况相反。这些不显示任何执行前计划信息,但包含执行后计划。这反映了触发器的基于集合的本质;每个受影响的行都触发一次,而不是每行触发一次。


@PaulWhite是否有充分的理由在请求估算的执行计划时不显示触发计划?这似乎是一个有用的缺失功能。我可能会为其创建一个连接项。
usr 2015年

@usr-也许是因为所选的实际缓存计划可能会根据此处所述的实际行数而有所不同?technet.microsoft.com/en-us/library/…–
马丁·史密斯

@MartinSmith可能是一个原因。最近,用于检查和fk约束的执行计划的连接项被标记为已完成,因此我希望它们可以对触发器执行相同的操作。
usr

@usr- 这是这里吗?3个月?对于新功能请求,这一定是一个记录周转!
马丁·史密斯

@MartinSmith是的,那个。1-2年前被“修复”。我真的希望我不必查询查询存储。我曾希望单击SSMS中的一个按钮。实际上,我很惊讶地看到引擎多年没有碰到的任何变化。但是也许没有。
usr 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.