SQL Server中内联表值函数的成本

4

在SQL Server 2008中,使用内联表值函数是否会带来与直接内联SQL不同的成本?我们的应用程序非常频繁地使用内联表值函数来重用常见查询,但最近发现,如果不使用它们,查询运行速度更快。

考虑以下情况:

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秒。

在这种情况下,使用表值函数的开销让我有些困惑。我没有预料到这一点。我们的应用程序中有很多表值函数,所以我想知道是否有什么我漏掉了。

4个回答

3
在这种情况下,UDF 应该像视图一样被展开,且应该是透明的。
显然,它不是...
在这种情况下,我猜测列是 smalldatetime,并且由于 UDF 参数而转换为 datetime,但常量在内联时会正确评估(以匹配列数据类型)。
datetime 的优先级高于 smalldatetime,因此列将被转换。
查询计划怎么说?UDF 将显示扫描,内联则很可能是搜索(不是 100%,只是基于我之前看到的)。
编辑: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秒就可以运行。 - Linus
当使用'7/24/2008',然后在行内使用dbo.Date(2008,7,24)时会发生什么? - gbn

0
一个可能会减慢函数速度的问题是在函数内省略表引用中的dbo.。这会导致SQL Server对每个调用进行安全检查,这可能是昂贵的。

3
仅在编译/重用时。下一次运行(相同的查询、相同的用户等),它将是正常的。 - gbn
1
我们不会省略dbo.,所以这不应该是问题所在。而且,即使有额外开销,我也无法想象它会导致14秒的延迟。 - Linus

0

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

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


0
在您的第二个示例中,表值函数必须返回整个数据集,然后查询才能应用过滤器。跨越TF边界并不是优化器总是能够做到的事情。
在第三个示例中,查询优化器可以确定用户只想要前几个“amounts”。如果这不是聚合值,则优化器可以将该处理推到查询的开头,并且不需要处理任何其他数据。如果它是一个聚合金额,则减速是由于不同的原因。
如果您比较这两个查询的查询计划,您应该会发现它们是不同的。

这仅适用于多语句表值函数。而且当它发生时,您无法看到内部计划。您只能从SQL分析器中推断IO和CPU。 - gbn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接