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

pet*_*ter 11 sql-server execution-plan functions merge-replication

我在 SQL 服务器上有这个查询,一个合并复制查询:

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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

  1. 上面的查询

没有关于功能。为什么实际方案中缺少功能信息?

我尝试了这些选项:

SET STATISTICS PROFILE ON
SET STATISTICS XML ON
Run Code Online (Sandbox Code Playgroud)

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

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


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

Pau*_*ite 17

和功能无关。为什么实际方案中缺少功能信息?

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

定义中包含BEGIN和 的函数END为每个输入行创建一个新的 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;
Run Code Online (Sandbox Code Playgroud)

执行前计划

执行前计划(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;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

SSMS 执行后

可以使用SQL Server Profiler 中的Showplan XML Statistics Profile Event Class,使用多次调用该函数的查询(每个输入行一次)来显示其他方式的性能影响:

SELECT TOP (5)
    p.ProductID,
    dbo.DumbNameLookup(p.ProductID)
FROM Production.Product AS p;
Run Code Online (Sandbox Code Playgroud)

探查器输出:

跟踪输出

函数执行有五个单独的执行后计划,父查询有一个。五个函数计划在分析器下部窗格中如下所示:

功能计划

父查询计划是:

家长计划

执行不带TOP (5)子句的查询会为 Product 表中的 504 行中的每一行生成完整的执行计划。您可能会看到这将如何在更大的表中迅速失控。

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