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)
P.S. Using the BETWEEN
operator does not help - SQL Server calls the scalar function twice anyway.
We can update multiple columns by specifying multiple columns after the SET command in the UPDATE statement. The UPDATE statement is always followed by the SET command, it specifies the column where the update is required.
The SQL AND condition and OR condition can be combined to test for multiple conditions in a SELECT, INSERT, UPDATE, or DELETE statement. When combining these conditions, it is important to use parentheses so that the database knows what order to evaluate each condition.
You should never use a scalar function in a where clause as indexes can't be used and frequently a full table scan is required. And if you need to force the CTE part of the query to execute first then you can materialise the results into a temp table and then select from that.
An SQL scalar function is a user-defined function written in SQL and it returns a single value each time it is invoked. SQL scalar functions contain the source code for the user-defined function in the user-defined function definition. There are two kinds of SQL scalar functions, inlined and compiled.
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.
Try the BETWEEN operator.
WHERE functionCall(..) BETWEEN minValue AND maxValue
http://www.w3schools.com/sql/sql_between.asp
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With