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

时间:2012-11-14 12:44:40

标签: sql sql-server tsql

有没有办法修改以下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都会调用标量函数两次。

3 个答案:

答案 0 :(得分:5)

尝试 BETWEEN 运算符。

WHERE functionCall(..) BETWEEN minValue AND maxValue

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

答案 1 :(得分: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

虽然表值函数返回表,但 可以 选择仅使用一个字段重新调整一行。然后,您将其有效地用作标量函数 - 但是,您可以获得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搜索网页,我相信你会得到更多。

答案 2 :(得分:3)

你可以尝试使用BETWEEN(如下所示),虽然你需要测试它,因为我有一个潜行的怀疑,数据库可能将其拆分出来执行它&gt; =和&lt; =无论如何.. < / p>

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