2012-11-14 69 views
6

是否有任何方法修改以下UPDATE語句,以便標量函數只被調用一次而不是兩次?避免在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無論如何都調用兩次標量函數。

回答

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 

雖然表值函數返回表,你可以選擇一個領域retun只有一行。然後,您將它有效地用作標量函數 - 但是,您將獲得SQL Server如何優化以上查詢的所有好處...
- 如果TVF是Inline (而不是多語句)
- 該TVF被擴展出到查詢
- 其結果是性能比dramatiaclly標量函數


實施例內聯表值函數更好:

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

如果SEACH網絡爲INLINE CROSS APPLY SCALAR FUNCTION PERFORMANCE我敢肯定,你會得到一大堆更多。

+0

謝謝。似乎沒有別的選擇,只能放棄標量函數來支持表值函數。 – 10p

+0

@ 10p - 當應用於整個數據集時,* *的效率更高。 – MatBailie

5

嘗試BETWEEN運營商

WHERE functionCall(..) BETWEEN minValue AND maxValue 

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

+1

好想法。儘管如此,這可能會擴展到'<=' and '> ='。 –

+0

我會測試它在這種情況下不會調用兩次,謝謝 – 10p

+0

無論如何SQL Server調用標量函數兩次,我猜這只是一個不同的表示法,所以這個建議並不真正解決問題 – 10p

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 
+0

我upvoted你解決方案,但user1660584在那裏第一個 – 10p

+0

你說得對 - SQL Server無論如何執行兩次 – 10p