Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid calling a scalar function multiple times in an UPDATE statement

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.

like image 856
10p Avatar asked Nov 14 '12 12:11

10p


People also ask

Can we update more than one value using update statement?

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.

How do you update a table with multiple conditions?

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.

Can we use scalar function in where clause in SQL?

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.

What are scalar functions in SQL example?

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.


3 Answers

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.

like image 156
MatBailie Avatar answered Nov 14 '22 22:11

MatBailie


Try the BETWEEN operator.

WHERE functionCall(..) BETWEEN minValue AND maxValue

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

like image 43
amik Avatar answered Nov 14 '22 22:11

amik


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
like image 41
StevieG Avatar answered Nov 14 '22 22:11

StevieG