简体   繁体   中英

how to avoid calling cpu intensive function repeatedly for sum()?

I have a function that performs a cpu heavy calculation on a passed id I am working on a report to summarize the results, but for performance reasons I only want to call the function once per id

Here is a simple example of the working SQL BUT it calls the function once for each column. How can I rewrite the query to only call the function once per identifier?

    SELECT 
    SUM( case myfunction(employee_id) WHEN 'bob' THEN 1 ELSE 0 END) as "bob total",
        SUM( case myfunction(employee_id) WHEN 'joe' THEN 1 ELSE 0 END) as "Joe total",
    SUM( case myfunction(employee_id) WHEN 'tom' THEN 1 ELSE 0 END) as "Toms total"
    FROM employee

You can just put the logic in a subquery before doing the sum, then reference the single column.

SELECT 
    SUM( case FunctionResult WHEN 'bob' THEN 1 ELSE 0 END) as "bob total",
    SUM( case FunctionResult WHEN 'joe' THEN 1 ELSE 0 END) as "Joe total",
    SUM( case FunctionResult WHEN 'tom' THEN 1 ELSE 0 END) as "Toms total"
FROM    
    (   SELECT myfunction(employee_id) AS FunctionResult
        FROM employee
    ) AS e;

A better solution in terms of performance though would be to look at what your scalar function actually does, and ask yourself does it need to be a function, can you make the solution set based?

Instead of FROM employee , use a derived table that is defined like this:

SELECT *, myfunction(employee_id) AS myFuncResult
FROM employee

Now, you have myFuncResult as an additional column. Let's hope the optimizer does not mess with this strategy. It does not have a good understanding of scalar function cost (in fact, none).

Since you are using SQL Server you could try the CROSS APPLY expression, just replace .Result with the name of the column that your function returns:

SELECT 
    SUM( case func.Result WHEN 'bob' THEN 1 ELSE 0 END) as "bob total",
    SUM( case func.Result WHEN 'joe' THEN 1 ELSE 0 END) as "Joe total",
    SUM( case func.Result WHEN 'tom' THEN 1 ELSE 0 END) as "Toms total"
FROM employee e
CROSS APPLY myfunction(e.employee_id) as func

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM