Is there any way to modify the following UPDATE
statement so that the scalar function is called only once, not twice?
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)
PS Using the BETWEEN
operator does not help - SQL Server calls the scalar function twice anyway.
Try the BETWEEN operator.
WHERE functionCall(..) BETWEEN minValue AND maxValue
This is often significantly more performant, but requires you to change the scalar function to an inline table valued function.
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
Although table valued functions return tables, you can choose to retun just one row with one field. Then you're using it effectively as a scalar function - But, you get all the benefits of how SQL Server can optimise the query above...
- If the TVF is Inline (and not multi-statement)
- The TVF gets expanded out into the query
- The result is performance dramatiaclly better than scalar functions
Example Inline Table Valued Function:
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
)
Deliberately trivial
One example post about this: scalar-functions-inlining-and-performance
If you seach the web for INLINE CROSS APPLY SCALAR FUNCTION PERFORMANCE
I'm sure you'll get a whole lot more.
You could try using BETWEEN (as below), although you'd need to test it as I've got a sneaking suspicion the database might split this out to execute it as >= and <= anyway..
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.