【问题标题】:Cost of Inline Table Valued function in SQL ServerSQL Server 中内联表值函数的成本
【发布时间】:2009-08-19 16:42:57
【问题描述】:

如果直接内联 SQL,则在 SQL Server 2008 中使用内联表值函数是否存在固有成本?我们的应用程序大量使用内联表值函数来重用常见查询,但最近,我们发现如果不使用它们,查询运行得更快。

考虑一下:

CREATE FUNCTION dbo.fn_InnerQuery (@asOfDate DATETIME)
RETURNS TABLE
AS
RETURN
(
   SELECT ... -- common, complicated query here
)

现在,当我这样做时:

SELECT TOP 10 Amount FROM dbo.fn_InnerQuery(dbo.Date(2009,1,1)) ORDER BY Amount DESC

查询会在大约 15 秒后返回结果。

但是,当我这样做时:

SELECT TOP 10 Amount FROM 
(
   SELECT ... -- inline the common, complicated query here
) inline
ORDER BY Amount DESC

查询在不到 1 秒内返回。

在这种情况下,我对使用表值函数的开销感到有些困惑。我没想到的是。我们的应用程序中有大量表值函数,所以我想知道这里是否缺少一些东西。

【问题讨论】:

    标签: sql-server sql-server-2008


    【解决方案1】:

    在这种情况下,UDF 应该像视图一样取消嵌套/展开,并且应该是透明的。

    显然不是……

    在这种情况下,我的猜测是该列是 smalldatetime,并且由于 udf 参数而被强制转换为 datetime,但是当内联时该常量被正确评估(以匹配列数据类型)。

    datetime 的优先级高于 smalldatetime,因此该列将被强制转换

    查询计划说明了什么? UDF 会显示扫描,内联最有可能是搜索(不是 100%,仅基于我之前看到的内容)

    编辑:Blog post by Adam Machanic

    【讨论】:

    • gbn,感谢您的链接。我将不得不更深入地研究它。 UDF 的执行计划似乎比内联版本复杂得多,尽管我不太清楚为什么会这样。看来我传递参数的方式会改变行为。 SELECT TOP 10 Amount FROM dbo.fn_InnerQuery(dbo.Date(2008,7,24)) ORDER BY Amount 运行时间为 15 秒。 SELECT TOP 10 Amount FROM dbo.fn_InnerQuery('7/24/2008') ORDER BY Amount 运行时间小于 1。
    • 使用 '7/24/2008' 然后 dbo.Date(2008,7,24) inline 会发生什么?
    【解决方案2】:

    可能会减慢函数速度的一件事是省略 dbo。来自函数内部的表引用。这会导致 SQL Server 对每个调用进行安全检查,这可能会很昂贵。

    【讨论】:

    • 仅在编译/重用时。下一次运行(相同的查询,相同的用户等)就可以了
    • 我们不会省略 dbo。所以不应该这样。此外,即使有开销,我也不会想象会有 14 秒的开销。
    【解决方案3】:

    尝试独立运行表值函数,看看它的执行速度有多快/多慢?

    另外,我不确定如何清除 SQL Server 在 UDF 执行中可能保留的执行缓存(?)。我的意思是 - 如果您首先运行 UDF,则可能是 SQL Server 具有实际查询并且它可以缓存计划/结果。因此,如果您单独运行复杂的查询 - 它可能会从缓存中运行。

    【讨论】:

      【解决方案4】:

      在您的第二个示例中,表值函数必须返回整个数据集,然后查询才能应用过滤器。跨越 TF 边界并不是优化器总能做的事情。

      在第三个示例中,查询优化器可以计算出用户只想要前几个“金额”。如果这不是一个聚合值,则优化器可以将该处理推送到查询的开头,而不用打扰任何其他数据。如果它是一个总量,那么放缓是出于不同的原因。

      如果您比较两个查询的查询计划,您应该会发现它们是不同的。

      【讨论】:

      • 这仅适用于多语句表值函数。当它发生时,你看不到内部计划。你只能从 SQL 分析器推断 IO 和 CPU
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-04
      • 2023-03-09
      • 1970-01-01
      • 2019-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多