避免在UPDATE语句中多次调用标量函数

10p*_*10p 6 sql t-sql sql-server

有没有办法修改以下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)
Run Code Online (Sandbox Code Playgroud)

PS使用BETWEEN运算符没有帮助 - SQL Server无论如何都会调用标量函数两次.

ami*_*mik 5

试试BETWEEN运算符.

WHERE functionCall(..) BETWEEN minValue AND maxValue
Run Code Online (Sandbox Code Playgroud)

http://www.w3schools.com/sql/sql_between.asp


Mat*_*lie 5

这通常性能更高,但要求您将标量函数更改为内联表值函数.

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
Run Code Online (Sandbox Code Playgroud)

虽然表值函数返回表,但您可以选择仅使用一个字段重新调整一行.然后你有效地使用它作为标量函数 - 但是,你得到了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
)
Run Code Online (Sandbox Code Playgroud)

故意琐碎

关于此的一个示例帖子: 标量函数 - 内联 - 和 - 性能

如果你搜索网页,INLINE CROSS APPLY SCALAR FUNCTION PERFORMANCE我相信你会得到更多.