Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2005 使用需要出现在Select和Where子句中的标量UDF的最佳方法_Sql Server 2005 - Fatal编程技术网

Sql server 2005 使用需要出现在Select和Where子句中的标量UDF的最佳方法

Sql server 2005 使用需要出现在Select和Where子句中的标量UDF的最佳方法,sql-server-2005,Sql Server 2005,我需要在select语句中包含一个昂贵的标量UDF,并使用该值来缩小where子句中的结果范围。UDF从当前行获取参数,因此我不能将其存储在一个变量中并从中选择 每行运行两次UDF感觉不太对劲: Select someField, someOtherField, dbo.MyExpensiveScalarUDF(someField, someOtherField) from someTable where dbo.MyExpensiveScalarUDF(some

我需要在select语句中包含一个昂贵的标量UDF,并使用该值来缩小where子句中的结果范围。UDF从当前行获取参数,因此我不能将其存储在一个变量中并从中选择

每行运行两次UDF感觉不太对劲:

Select someField, 
       someOtherField, 
       dbo.MyExpensiveScalarUDF(someField, someOtherField)
from someTable
where dbo.MyExpensiveScalarUDF(someField, someOtherField) in (aHandfulOfValues)

我如何清理它,使函数每行只运行一次

在我回答这个具体问题之前,我需要更多的细节,但我马上想到了两个基本想法:

(1) 你能把它变成一个基于表的函数,加入FROM子句,然后从那里开始工作吗


(2) 查看外部应用和交叉应用连接子句。本质上,它们允许对基于表的函数进行联接,其中传递给函数的参数基于被联接的行(而不是单个调用)。BOL中有这方面的好例子。

在解决这个具体问题之前,我需要更多的细节,但我马上想到了两个基本概念:

(1) 你能把它变成一个基于表的函数,加入FROM子句,然后从那里开始工作吗


(2) 查看外部应用和交叉应用连接子句。本质上,它们允许对基于表的函数进行联接,其中传递给函数的参数基于被联接的行(而不是单个调用)。BOL就是一个很好的例子。

仅仅因为您两次提到该函数并不意味着每行将计算两次。幸运的是,查询优化器每行只计算一次。它是否存在可能部分取决于UDF是确定性的还是非确定性的

看看估计的执行计划。也许你会发现你什么都不担心

如果计算了两次,您可以尝试一下,看看它是否会改变计划,但仍然不能保证:

WITH T(someField,someOtherField,expensiveResult) as (
  select someField, someOtherField, dbo.MyExpensiveScalarUDF(someField, someOtherField)
  from someTable
)
  select * from T
  where expensiveResult in (thisVal,thatVal,theotherVal);

仅仅因为您碰巧两次提到该函数,并不意味着它每行将被计算两次。幸运的是,查询优化器每行只计算一次。它是否存在可能部分取决于UDF是确定性的还是非确定性的

看看估计的执行计划。也许你会发现你什么都不担心

如果计算了两次,您可以尝试一下,看看它是否会改变计划,但仍然不能保证:

WITH T(someField,someOtherField,expensiveResult) as (
  select someField, someOtherField, dbo.MyExpensiveScalarUDF(someField, someOtherField)
  from someTable
)
  select * from T
  where expensiveResult in (thisVal,thatVal,theotherVal);

Steve是正确的-如果UDF是确定性的,查询计划可能不会重新计算相同的表达式

但是,重复自己是一个潜在的维护问题:

WITH temp AS (
Select someField, 
       someOtherField, 
       dbo.MyExpensiveScalarUDF(someField, someOtherField) AS scalar
from someTable
)
SELECT *
FROM temp
where scalar in (aHandfulOfValues)
您可以使用CTE或嵌套查询来避免它


对于任何重要大小的行集(比如50万次评估),如果可能的话,最好避免使用标量UDF。如果您在这里内联扩展它(使用CTE,您不必重复自己的操作),您可能会发现一个巨大的性能提升。标量UDF应该是最后的手段。根据我的经验,在依赖标量UDF之前,最好使用持久化计算列、内联或任何其他技术。

Steve是正确的-如果UDF是确定性的,查询计划可能不会重新计算相同的表达式

但是,重复自己是一个潜在的维护问题:

WITH temp AS (
Select someField, 
       someOtherField, 
       dbo.MyExpensiveScalarUDF(someField, someOtherField) AS scalar
from someTable
)
SELECT *
FROM temp
where scalar in (aHandfulOfValues)
您可以使用CTE或嵌套查询来避免它


对于任何重要大小的行集(比如50万次评估),如果可能的话,最好避免使用标量UDF。如果您在这里内联扩展它(使用CTE,您不必重复自己的操作),您可能会发现一个巨大的性能提升。标量UDF应该是最后的手段。根据我的经验,在依赖标量UDF之前,最好使用持久化计算列、内联或任何其他技术。

谢谢-这将执行时间从大约40秒减少到了不到1秒。太好了!感谢您提供有关其工作原理的反馈。这种技术/语法有名称吗?“WITH”子句中的表T称为CTE(公共表表达式),但我不知道使用CTE(或等效子查询)的技术的特定名称为了避免重复一个表达式。谢谢-这将执行时间从大约40秒降低到1秒以下。太好了!感谢您提供有关其工作原理的反馈。这种技术/语法有名称吗?“WITH”子句中的表T称为CTE(公共表表达式),但我不知道使用CTE(或等效子查询)以避免重复表达式的技术的特定名称。说得好,Cade。至少当标量计算是单个表达式时,通常最好使用返回(SELECT)的表值UDF替换标量UDF,然后使用交叉应用编写查询。一开始看起来很笨拙,但最终它开始感觉正常,而且效果很好。说得好,凯德。至少当标量计算是单个表达式时,通常最好使用返回(SELECT)的表值UDF替换标量UDF,然后使用交叉应用编写查询。一开始看起来很笨拙,但最终它开始感觉正常,并且运行良好。