SQL function performance

两盒软妹~` 提交于 2020-01-05 17:22:09

问题


I have this function which is used on my view.

FUNCTION [dbo].[CalculateAmount] (
@ID INT,
@PRICE DECIMAL(24,4)) 

declare @computedValue decimal(24,4)

set @computedValue = case when 
(select TABLE1.ID
FROM dbo.[TABLE1] TABLE1
JOIN dbo.[TABLE2] TABLE2 ON TABLE2.ID = TABLE1.ID
WHERE TABLE1.ID = @ID // some conditions here //
Is null
then @PRICE 
else
@PRICE * CAST('1.0368' as decimal(24,4))
end

So basically, I wanted to check if the ID passed as parameter is existing on TABLE1. If it returned a row, multiply the Price to 1.0368, if not then the Price will remain as is.

My problem here is the performance. I am using this on view which returns 17000 rows. Now my view is currently running, 45 minutes on 12000th row.

Any ideas or suggestion to improve the performance of my view?

EDIT

I am calling this on my view like this:

[dbo].[CalculateAmount](ID, PRICE) AS PRICE

along with the select statement.


回答1:


If the only place you use your function is in the view, then why not just encapsulate the logic in the view:

ALTER VIEW dbo.YourView
AS
    SELECT  <columns>,
            CalculatedPrice = CASE WHEN t1.ID IS NULL THEN <tables>.Price 
                                    ELSE 1.0368 * <tables>.Price 
                                END
    FROM    <tables>
            OUTER APPLY
            (   SELECT  TOP 1 t1.ID
                FROM    dbo.Table1 AS t1
                        INNER JOIN dbo.Table2 AS t2
                            ON t2.ID = t1.ID
                WHERE   t1.ID = <tables>.ID
                --      More Conditions
            ) AS t1
    WHERE   <predicates>;

The outer apply simply does the same check as your function to see if a record exists, then in the select statement, when a match is not found the price is multiplied by your constant, otherwise it is multiplied by 1.

You could create an inline table valued function for this. Unlike a scalar UDF this is not executed RBAR, but the query plan is expanded out into the outer query:

CREATE FUNCTION dbo.CalculateAmount (@ID INT, @Price DECIMAL(24, 4)
RETURNS TABLE
AS
RETURN
(   SELECT  Price = CASE WHEN COUNT(*) = 0 THEN @Price
                        ELSE @Price * 1.0368
                    END
    FROM    dbo.Table1 AS t1
            INNER JOIN dbo.Table2 AS t2
                ON t2.ID = t1.ID
    WHERE   t1.ID = @ID
);

Then you would call it as:

SELECT  <columns>,
        CalculatedPrice = ca.Price
FROM    <tables>
        OUTER APPLY dbo.CalculateAmount(ID, Price) AS ca
WHERE   <predicates>;



回答2:


From performance point of view,knowing more details is important.

i ) first of all,it is known fact that UDF always degrade performance specially when it fire for lot of rows.

ii) What is written inside view.May be your requirement can be adjusted inside view itself,so no need of function of any kind.

like you side you want to know only if is exists in table1 so you can use outer apply

your sample view code ,

Select ,case when tvf.id is null then price else price*1.0368 end as Price
from other table
outer apply (Select id from dbo.table1 A where A.id=othertable.id )tvf

I think you should do this only .you should remove all UDF inside this view.

iii) Most importantly,how much time your view take to execute without this function ?




回答3:


Not too much you can do with this function performance because this SELECT with JOIN will execute for every 17000 rows and it must be slow. You can add some indexex to TABLE1, TABLE2 but in my opinion it is the wrong way. Try to move this query to your view and leave in function only logic about price, for example:

FUNCTION [dbo].[CalculateAmount] (
@ID INT,
@PRICE DECIMAL(24,4)) 

declare @computedValue decimal(24,4)

case 
   when @PRICE Is null
      then @PRICE 
   else
      @PRICE * CAST('1.0368' as decimal(24,4))
end

and view:

select dbo.CalculateAmount(tmp.ID, PRICE) as Price, *
from SomeTable s
left join
(
select distinct TABLE1.ID
FROM dbo.[TABLE1] TABLE1
JOIN dbo.[TABLE2] TABLE2 ON TABLE2.ID = TABLE1.ID
WHERE // some conditions here //
) tmp on tmp.ID=s.tmpID


来源:https://stackoverflow.com/questions/36711049/sql-function-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!