避免在 UPDATE 语句中多次调用标量函数
Posted
技术标签:
【中文标题】避免在 UPDATE 语句中多次调用标量函数【英文标题】:Avoid calling a scalar function multiple times in an UPDATE statement 【发布时间】:2012-11-14 12:44:40 【问题描述】:有没有办法修改下面的UPDATE
语句,使标量函数只被调用一次,而不是两次?
UPDATE a
SET SomeField = b.SomeField
FROM TableA AS a
JOIN TableB b ON b.Link = a.Link
WHERE b.CostMin <= @Cost * dbo.OneScalarFunction(@CurrencyFrom, b.Currency)
AND b.CostMax >= @Cost * dbo.OneScalarFunction(@CurrencyFrom, b.Currency)
P.S. 使用 BETWEEN
运算符没有帮助 - SQL Server 无论如何都会调用标量函数两次。
【问题讨论】:
【参考方案1】:这通常显着提高性能,但需要您将标量函数更改为内联表值函数。
UPDATE
a
SET
SomeField = b.SomeField
FROM
TableA AS a
CROSS APPLY
dbo.oneInlineTableValuedFunction(@CurrencyFrom, e.Currency) AS ITVF
INNER JOIN
TableB b
ON b.Link = a.Link
WHERE
b.CostMin <= @Cost * ITVF.exchangeRate
AND b.CostMax >= @Cost * ITVF.exchangeRate
虽然表值函数返回表,但您可以选择只返回一行和一个字段。然后,您可以有效地将其用作标量函数 - 但是,您将获得 SQL Server 如何优化上述查询的所有好处... - 如果 TVF 是内联(而不是多语句) - TVF 扩展到查询中 - 结果是性能明显优于标量函数
内联表值函数示例:
CREATE FUNCTION dbo.oneInlineTableValuedFunction (
@currencyFrom VARCHAR(32),
@currencyTo VARCHAR(32)
)
RETURNS TABLE
AS
RETURN (
SELECT
exchangeRate
FROM
dbo.someTable
WHERE
currencyFrom = @currencyFrom
AND currencyTo = @currencyTo
)
故意琐碎
关于此的示例帖子:scalar-functions-inlining-and-performance
如果你在网上搜索INLINE CROSS APPLY SCALAR FUNCTION PERFORMANCE
,我相信你会得到更多。
【讨论】:
谢谢。似乎别无选择,只能放弃标量函数以支持表值函数。 @10p - 当应用于整个数据集时,它们效率大大提高。【参考方案2】:试试 BETWEEN 运算符。
WHERE functionCall(..) BETWEEN minValue AND maxValue
http://www.w3schools.com/sql/sql_between.asp
【讨论】:
好主意。在实践中,这可能会扩展到<=
和>=
。
SQL Server 还是调用了标量函数两次,我猜只是符号不同,所以这个建议并不能真正解决问题【参考方案3】:
您可以尝试使用 BETWEEN(如下所示),尽管您需要对其进行测试,因为我偷偷怀疑数据库可能会将其拆分为 >= 和
UPDATE a
SET SomeField = b.SomeField
FROM TableA AS a
JOIN TableB b ON b.Link = a.Link
WHERE @Cost * dbo.OneScalarFunction(@CurrencyFrom, e.Currency) BETWEEN b.CostMin AND b.CostMax
【讨论】:
以上是关于避免在 UPDATE 语句中多次调用标量函数的主要内容,如果未能解决你的问题,请参考以下文章