避免在 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

【讨论】:

好主意。在实践中,这可能会扩展到&lt;=&gt;= 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 语句中多次调用标量函数的主要内容,如果未能解决你的问题,请参考以下文章

OpenCL:如何避免重复的标量/向量函数?

使用 forEach 时避免回调多次调用

优化 MySQL 查询,避免对用户自定义函数的不必要调用

避免在不同实​​例中多次执行一个函数

C++并发,同步设计,避免多次执行问题

PHP 小技巧之如何避免参数多次传递?