我有一个昂贵的标量UDF,我需要在SELECT语句中包含并使用该值缩小where子句中的结果。 该UDF需要从当前行参数,所以我不能只是将其存放在var和从该选择。
每行运行UDF两次只是感觉不对:
Select someField,
someOtherField,
dbo.MyExpensiveScalarUDF(someField, someOtherField)
from someTable
where dbo.MyExpensiveScalarUDF(someField, someOtherField) in (aHandfulOfValues)
如何清理这件事使该功能只每行运行一次?
只是因为你碰巧提功能两次并不意味着它会每行的两倍计算。 幸运的是,查询优化器将计算其每行只有一次。 无论它是否可能部分取决于该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 temp AS (
Select someField,
someOtherField,
dbo.MyExpensiveScalarUDF(someField, someOtherField) AS scalar
from someTable
)
SELECT *
FROM temp
where scalar in (aHandfulOfValues)
你可以用一个CTE或嵌套查询避免它。
标量UDF是最好的,如果任何显著大小(比如说五周十万的评估)的行集在所有可能避免。 如果你展开它内嵌在这里(和一个CTE你将不必重复自己),你可能会发现一个巨大的性能提升。 标量UDF应该是最后的手段。 在我的经验,你好得多依靠标量UDF之前,使用一个持久化计算列或行内或几乎任何其他技术。
我需要更多的细节之前,我可以解决这个具体问题,而是两个总体思路打我马上:
(1)你可以把它基于表格的函数,从那里加入它在FROM子句中,和工作?
(2)寻找到外APPLY和CROSS APPLY加入条款。 从本质上讲,它们允许连接上基于表格的函数,其中传递到该函数的参数是基于所述行被连接(而不是一个单一的呼叫)。 就是很好的例子是在BOL。
文章来源: Best way to use a Scalar UDF that needs to appear in the Select and Where clauses