SQLServer:为什么要避免表值用户定义函数?

问题描述 投票:0回答:4

我有一个相当大的查询,需要在多个存储过程中使用,我想将其转换为 UDF 以使其更易于维护(视图不起作用,这需要一堆参数),但是与我交谈过的每个人都告诉我 UDF 非常慢。

虽然我不知道到底是什么让它们变慢,但我会猜测它们是变慢的,但鉴于我没有在联接中使用这个 UDF,而是返回一个表变量,我认为它不会别那么糟糕。

所以我想问题是,我应该不惜一切代价避免 UDF 吗?谁能指出具体证据表明它们速度较慢?

sql-server query-optimization user-defined-functions
4个回答
4
投票

标量 UDF 非常慢,内联 UDF 实际上是宏,因此它们非常快: 几篇文章:

通过表值 UDF 重用您的代码

许多嵌套内联 UDF 非常快

有关标量 UDF 缓慢的更多链接:

具有日期时间参数的 UDF 的 SQL Server 性能模式

并非所有 UDF 都不利于性能


3
投票

正如您所指出的,(表)udf 的结果不会连接到任何内容,那么不应对性能产生任何影响。

要尝试解释一下为什么 UDF 会被认为很慢(实际上只是以错误的方式使用),请考虑以下示例;

我们有表 A 和表 B。假设我们有一个像这样的连接

选择 A.col1, A.col2, B.ColWhatever 从 一个 将 B 连接到 A.aid = b.fk_aid 在哪里 B.someCol = @param1 AND A.anotherCol = @param2

在这种情况下,SQL Server 将尽力以它知道的最高效的方式返回结果。 其中一个主要因素是减少磁盘读取。因此 - 它将使用 JOIN 和 where 子句中的条件来评估(希望使用索引)要返回多少行。

现在 - 假设我们提取部分条件用于限制返回到 UDF 的数据量。现在——查询优化器无法再从磁盘拉回最小数量的行,它只能处理它提供的条件。 简而言之,表 udf 始终会被评估,并且数据会在返回到主存储过程之前返回,因此,如果原始连接中存在其他一些可能导致磁盘读取次数减少的条件,则这只适用于数据被拉入存储过程后。

假设我们创建一个 UDF 来从表 B 中选择与 where 子句匹配的行。如果表 B 中有 100k 行,其中 50% 满足 where 子句的条件 - 那么所有这些行将返回到存储过程以与表 A 进行比较。现在,如果现在只有 10% 的行与表 A 匹配我们只讨论了 B 表中我们想要使用的 5%,但我们已经撤回了 50%,其中大部分是我们不想要的!

如果这完全是胡言乱语,抱歉 - 请告诉我!


0
投票

您可以发布您的代码吗?一般来说,如果您在查询的 select 子句中使用标量 udf,则查询返回的每行都会执行 udf 中的语句一次。最好对名为 udf 的表执行联接,或者找到某种方法使用主 SQL 语句中的联接来执行 udf 中的逻辑。


-2
投票

是否有某种原因您不想使用存储过程而不是 UDF?

© www.soinside.com 2019 - 2024. All rights reserved.