SentryOne Plan Explorer 是否计算 UDF 中的读取次数?

Gab*_*abe 9 sql-server-2008 sql-server execution-plan functions query-performance

我有一个这样的查询:

select dbo.fn_complexFunction(t.id)
from mytable t
Run Code Online (Sandbox Code Playgroud)

SQL Sentry Plan Explorer 中,我注意到我必须运行 Get Estimated Plan 才能使查询计划包含 UDF。

运行“获取实际计划”时,逻辑读取和其他指标似乎不包括 UDF 中发生的操作。在这种情况下,使用 Profiler 是唯一的解决方法吗?

Aar*_*and 11

我们在这里遇到的最大问题是:

  1. 就像@JNK 所说的那样,SQL Server 混淆了 UDF 的使用,并且无论如何都会用它们做可怕的事情(就像总是估计一行)。当您在 SSMS 中生成实际计划时,您也根本看不到它的用途。计划资源管理器受到相同限制,因为它只能提供有关 SQL Server 提供的计划的信息。
  2. 在生成实际计划时,代码依赖于不同的运行时指标来源。不幸的是,计划 XML 不包括函数调用,并且 SQL Server 不会显示使用SET STATISTICS IO ON;任一函数时产生的 I/O (这是Table I/O选项卡填充的方式)。

考虑以下针对 AdventureWorks2012 的视图和函数。这只是在给定标题表中的随机行的情况下从详细信息表中返回随机行的愚蠢尝试 - 主要是为了确保我们每次生成尽可能多的 I/O。

CREATE VIEW dbo.myview 
WITH SCHEMABINDING
AS
  SELECT TOP (100000) rowguid, SalesOrderID, n = NEWID() 
    FROM Sales.SalesOrderDetail ORDER BY NEWID();
GO

CREATE FUNCTION dbo.whatever(@SalesOrderID INT)
RETURNS UNIQUEIDENTIFIER
WITH SCHEMABINDING
AS
BEGIN
  RETURN 
  (
    SELECT TOP (1) rowguid FROM dbo.myview 
     WHERE SalesOrderID = @SalesOrderID ORDER BY n
  );
END
GO
Run Code Online (Sandbox Code Playgroud)

Management Studio 会(和不会)告诉您什么

在 SSMS 中进行以下查询:

SET STATISTICS IO ON;

  SELECT TOP (5) SalesOrderID, dbo.whatever(SalesOrderID) 
    FROM Sales.SalesOrderHeader ORDER BY NEWID();

SET STATISTICS IO OFF;
Run Code Online (Sandbox Code Playgroud)

当您估计一个计划,你得到的查询计划一个单一的计划功能(而不是5,因为你可能希望如此):

Management Studio 中的预估计划

显然,您根本没有得到任何 I/O 数据,因为查询实际上并未执行。现在,生成一个实际的计划。您在结果网格中获得了您期望的 5 行,以下计划(绝对没有明显提及 UDF,除了在 XML 中您可以找到它作为查询文本的一部分和标量运算符的一部分):

Management Studio 中的实际计划

以及以下STATISTICS IO输出(绝对没有提及Sales.SalesOrderDetail,即使我们知道它必须从该表中读取):

表 'SalesOrderHeader'。扫描计数 1,逻辑读取 57,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。

计划探索者告诉您什么

当 PE 为同一查询生成估计计划时,它知道与 SSMS 相同的事情。但是,它确实以更直观的方式显示内容。例如,外部查询的估计计划显示了函数的输出如何与查询的输出组合,并且在单个计划图中立即清楚地表明两个表都有 I/O

计划资源管理器中的估计计划

它还单独显示了函数的计划,我只是为了完整性而包括在内:

计划资源管理器中 UDF 的估计计划

现在,让我们看一个实际的计划,它是有用的数千倍。这里的缺点是,它只包含 SQL Server 决定显示的信息,因此它只能显示 SQL Server 提供的图形计划图。在这种情况下,有人决定不向您展示有用的东西;它只是根据提供的计划 XML 一无所知。在这种情况下,就像在 SSMS 中一样,您只能看到外部查询的计划,就好像根本没有调用该函数

计划资源管理器中的实际计划

Table I/O 选项卡也仍然依赖于 的输出STATISTICS IO,它也忽略在函数调用中执行的任何活动:

计划资源管理器中实际计划的表 I/O

但是,PE 会为您获取整个调用堆栈。我偶尔听到有人问,“噗,我什么时候需要调用堆栈?” 好吧,您实际上可以分解每个函数调用所花费的时间、使用的 CPU 和读取次数(以及,对于 TVF,生成的行数)

计划资源管理器中的调用堆栈,显示 UDF 调用

不幸的是,您无法将其与 I/O 来自哪个表(同样,因为 SQL Server 不提供该信息)相关联,并且它没有标有 UDF 名称(因为它被捕获为临时语句,而不是函数调用本身)。但是它确实允许您看到,而 Management Studio 没有看到的是您的 UDF 是一只什么样的狗。你仍然需要加入一些点,但点较少,而且它们更接近。

关于探查器

最后,我强烈建议远离 Profiler,除非它是设置服务器端跟踪,您要编写脚本然后在任何 UI 工具的范围之外运行。对生产系统使用 Profiler 几乎肯定会导致比它解决的问题更多的问题。如果您想获取此信息,请使用服务器端跟踪或扩展事件,并确保非常明智地进行过滤。即使没有分析器,跟踪也会影响您的服务器,并且通过扩展事件检索节目计划也不是世界上最有效的事情

  • @Gabe 我不知道原因,抱歉。也许是为了让咨询更有利可图? (3认同)