Select Speed with slow function?

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 00:28:21



Hi,

I have this select statement (simplified)

SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS CUSTOMER_PRICE_WITH_TAX,
* FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'

Now, this execution takes 16 seconds.
If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.

So, each dbo.fnCalcPrice (which itself does serveral selects, checking
prices, depending on type (xyz) etc ) takes about 7 seconds.
Speeding up the function it self any more isnt possible.

Is there anyway to goaround having it to be running 2 times in the SQL query
with changing the clients? (I could do the tax calc on the client but dont
want to) and I need the price with and without tax (tax percent is stored on
the product).



But then you get "cannot use variables with data-retrieving operation.."

I could wrap everything in a stored procedure, but the where statements are
very complex and diffrent every time..

Any suggestions how to do the most efficiant query?

- Fredrik

 
 
 

Select Speed with slow function?

Post by Ivan Arjentinsk » Sat, 09 Mar 2002 01:13:51


Fredrik,

Are you sure that the function is executed 2 times? What happens if you
remove only 1 of the expressions?

If you are sure that the function is executed 2 times, try this:
SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
FROM (
    SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
    FROM INVENTORY
    WHERE PRODUCT_NAME = 'TEST%'
) X

--
Ivan Arjentinski
----------------------------------------------------------------------
Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
scripts), sample data (INSERT INTO....) and desired result set when asking
for assistance is highly appreciated
----------------------------------------------------------------------


Quote:> Hi,

> I have this select statement (simplified)

> SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS

CUSTOMER_PRICE_WITH_TAX,
> * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'

> Now, this execution takes 16 seconds.
> If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.

> So, each dbo.fnCalcPrice (which itself does serveral selects, checking
> prices, depending on type (xyz) etc ) takes about 7 seconds.
> Speeding up the function it self any more isnt possible.

> Is there anyway to goaround having it to be running 2 times in the SQL
query
> with changing the clients? (I could do the tax calc on the client but dont
> want to) and I need the price with and without tax (tax percent is stored
on
> the product).




> But then you get "cannot use variables with data-retrieving operation.."

> I could wrap everything in a stored procedure, but the where statements ar
e
> very complex and diffrent every time..

> Any suggestions how to do the most efficiant query?

> - Fredrik


 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 01:32:01


Thanks for the answer,
But that give the same performace, it actually runs the function twice.
So running that query takes 21 seconds, running only the subquery takes 12

- Fredrik


> Fredrik,

> Are you sure that the function is executed 2 times? What happens if you
> remove only 1 of the expressions?

> If you are sure that the function is executed 2 times, try this:
> SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> FROM (
>     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
>     FROM INVENTORY
>     WHERE PRODUCT_NAME = 'TEST%'
> ) X

> --
> Ivan Arjentinski
> ----------------------------------------------------------------------
> Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> scripts), sample data (INSERT INTO....) and desired result set when asking
> for assistance is highly appreciated
> ----------------------------------------------------------------------



> > Hi,

> > I have this select statement (simplified)

> > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> CUSTOMER_PRICE_WITH_TAX,
> > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'

> > Now, this execution takes 16 seconds.
> > If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.

> > So, each dbo.fnCalcPrice (which itself does serveral selects, checking
> > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > Speeding up the function it self any more isnt possible.

> > Is there anyway to goaround having it to be running 2 times in the SQL
> query
> > with changing the clients? (I could do the tax calc on the client but
dont
> > want to) and I need the price with and without tax (tax percent is
stored
> on
> > the product).

> > What I would like (which is not possible) is something like SELECT



.....
> > But then you get "cannot use variables with data-retrieving operation.."

> > I could wrap everything in a stored procedure, but the where statements
ar
> e
> > very complex and diffrent every time..

> > Any suggestions how to do the most efficiant query?

> > - Fredrik

 
 
 

Select Speed with slow function?

Post by Ivan Arjentinsk » Sat, 09 Mar 2002 01:48:02


Quote:> But that give the same performace, it actually runs the function twice.

Sorry, I didn't think this might happen. Are you sure? Did you add any other
clauses to the outer SQL?

A kind of workaround is to use temp table:

SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
INTO #Customer_Price_Temp
FROM INVENTORY
WHERE PRODUCT_NAME = 'TEST%'

SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
FROM #Customer_Price_Temp

DROP TABLE #Customer_Price_Temp

Another way would be to expand the function in the derived table (if
possible). You might ask the group for assistance on the combined problem,
e.g. the query and the function.
--
Ivan Arjentinski
----------------------------------------------------------------------
Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
scripts), sample data (INSERT INTO....) and desired result set when asking
for assistance is highly appreciated
----------------------------------------------------------------------


> Thanks for the answer,
> But that give the same performace, it actually runs the function twice.
> So running that query takes 21 seconds, running only the subquery takes 12

> - Fredrik



> > Fredrik,

> > Are you sure that the function is executed 2 times? What happens if you
> > remove only 1 of the expressions?

> > If you are sure that the function is executed 2 times, try this:
> > SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> > FROM (
> >     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> >     FROM INVENTORY
> >     WHERE PRODUCT_NAME = 'TEST%'
> > ) X

> > --
> > Ivan Arjentinski
> > ----------------------------------------------------------------------
> > Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> > scripts), sample data (INSERT INTO....) and desired result set when
asking
> > for assistance is highly appreciated
> > ----------------------------------------------------------------------



> > > Hi,

> > > I have this select statement (simplified)

> > > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> > CUSTOMER_PRICE_WITH_TAX,
> > > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'

> > > Now, this execution takes 16 seconds.
> > > If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.

> > > So, each dbo.fnCalcPrice (which itself does serveral selects, checking
> > > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > > Speeding up the function it self any more isnt possible.

> > > Is there anyway to goaround having it to be running 2 times in the SQL
> > query
> > > with changing the clients? (I could do the tax calc on the client but
> dont
> > > want to) and I need the price with and without tax (tax percent is
> stored
> > on
> > > the product).

> > > What I would like (which is not possible) is something like SELECT



> .....
> > > But then you get "cannot use variables with data-retrieving
operation.."

> > > I could wrap everything in a stored procedure, but the where
statements
> ar
> > e
> > > very complex and diffrent every time..

> > > Any suggestions how to do the most efficiant query?

> > > - Fredrik

 
 
 

Select Speed with slow function?

Post by Reinaldo Kibel ( » Sat, 09 Mar 2002 01:46:58


Great discussion.
Can you check Execution Plan? What does it do when 1 only call to
dbo.fnCalcPrice.
dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the index?
The WHERE clause is on PRODUCT_NAME. Is there index on both? Check from the
query plan that the optimizer is using this index.

Reinaldo Kibel
Microsoft? Corp. - SQL Server Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.

Additional support can be obtained at http://support.microsoft.com

Are you secure?  For information about the Strategic Technology Protection
Program and to order your FREE Security Tool Kit, please visit
http://www.microsoft.com/security.
--------------------


| Subject: Re: Select Speed with slow function?
| Date: Thu, 7 Mar 2002 18:13:51 +0200
| Lines: 65
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
| X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000

| Newsgroups: microsoft.public.sqlserver.programming
| NNTP-Posting-Host: 212.91.170.206
| Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
| Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
| X-Tomcat-NG: microsoft.public.sqlserver.programming
|
| Fredrik,
|
| Are you sure that the function is executed 2 times? What happens if you
| remove only 1 of the expressions?
|
| If you are sure that the function is executed 2 times, try this:
| SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
| FROM (
|     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
|     FROM INVENTORY
|     WHERE PRODUCT_NAME = 'TEST%'
| ) X
|
| --
| Ivan Arjentinski
| ----------------------------------------------------------------------
| Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
| scripts), sample data (INSERT INTO....) and desired result set when asking
| for assistance is highly appreciated
| ----------------------------------------------------------------------
|


| > Hi,
| >
| > I have this select statement (simplified)
| >
| > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
| > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
| CUSTOMER_PRICE_WITH_TAX,
| > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
| >
| > Now, this execution takes 16 seconds.
| > If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.
| >
| > So, each dbo.fnCalcPrice (which itself does serveral selects, checking
| > prices, depending on type (xyz) etc ) takes about 7 seconds.
| > Speeding up the function it self any more isnt possible.
| >
| > Is there anyway to goaround having it to be running 2 times in the SQL
| query
| > with changing the clients? (I could do the tax calc on the client but
dont
| > want to) and I need the price with and without tax (tax percent is
stored
| on
| > the product).
| >
| > What I would like (which is not possible) is something like SELECT



....
| > But then you get "cannot use variables with data-retrieving operation.."
| >
| > I could wrap everything in a stored procedure, but the where statements
ar
| e
| > very complex and diffrent every time..
| >
| >
| >
| > Any suggestions how to do the most efficiant query?
| >
| > - Fredrik
| >
| >
|
|
|

 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 05:18:36


Well, the execution plan is nothing more to do about what I can see.
 The problem is that the function does have to do up to 100 subquery's for
each row, so that takes time, I have indexes correctly, so its "speeded" up
as much as possible.

  |--Compute
Scalar(DEFINE:([Expr1002]=[dbo].[fnCALCULATED_PRICE](Convert([INVENTORY].[PR
ODUCT_ID]), 'STA')))
       |--Index
Scan(OBJECT:([D1000].[dbo].[INVENTORY].[INVENTORY_WEB_HINT_3]),
WHERE:([INVENTORY].[GROUP_NAME_1]= 'BILDSK?RMAR'))



> Great discussion.
> Can you check Execution Plan? What does it do when 1 only call to
> dbo.fnCalcPrice.
> dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the index?
> The WHERE clause is on PRODUCT_NAME. Is there index on both? Check from
the
> query plan that the optimizer is using this index.

> Reinaldo Kibel
> Microsoft? Corp. - SQL Server Support Engineer

> This posting is provided "AS IS" with no warranties, and confers no
rights.

> Additional support can be obtained at http://support.microsoft.com

> Are you secure?  For information about the Strategic Technology Protection
> Program and to order your FREE Security Tool Kit, please visit
> http://www.microsoft.com/security.
> --------------------


> | Subject: Re: Select Speed with slow function?
> | Date: Thu, 7 Mar 2002 18:13:51 +0200
> | Lines: 65
> | X-Priority: 3
> | X-MSMail-Priority: Normal
> | X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
> | X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000

> | Newsgroups: microsoft.public.sqlserver.programming
> | NNTP-Posting-Host: 212.91.170.206
> | Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
> | Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
> | X-Tomcat-NG: microsoft.public.sqlserver.programming
> |
> | Fredrik,
> |
> | Are you sure that the function is executed 2 times? What happens if you
> | remove only 1 of the expressions?
> |
> | If you are sure that the function is executed 2 times, try this:
> | SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> | FROM (
> |     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> |     FROM INVENTORY
> |     WHERE PRODUCT_NAME = 'TEST%'
> | ) X
> |
> | --
> | Ivan Arjentinski
> | ----------------------------------------------------------------------
> | Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> | scripts), sample data (INSERT INTO....) and desired result set when
asking
> | for assistance is highly appreciated
> | ----------------------------------------------------------------------
> |


> | > Hi,
> | >
> | > I have this select statement (simplified)
> | >
> | > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> | > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> | CUSTOMER_PRICE_WITH_TAX,
> | > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
> | >
> | > Now, this execution takes 16 seconds.
> | > If I remove one call to dbo.fnCalcPrice the execution takes 9 seconds.
> | >
> | > So, each dbo.fnCalcPrice (which itself does serveral selects, checking
> | > prices, depending on type (xyz) etc ) takes about 7 seconds.
> | > Speeding up the function it self any more isnt possible.
> | >
> | > Is there anyway to goaround having it to be running 2 times in the SQL
> | query
> | > with changing the clients? (I could do the tax calc on the client but
> dont
> | > want to) and I need the price with and without tax (tax percent is
> stored
> | on
> | > the product).
> | >
> | > What I would like (which is not possible) is something like SELECT



> ....
> | > But then you get "cannot use variables with data-retrieving
operation.."
> | >
> | > I could wrap everything in a stored procedure, but the where
statements
> ar
> | e
> | > very complex and diffrent every time..
> | >
> | >
> | >
> | > Any suggestions how to do the most efficiant query?
> | >
> | > - Fredrik
> | >
> | >
> |
> |
> |

 
 
 

Select Speed with slow function?

Post by Umachandar Jayachandra » Sat, 09 Mar 2002 05:56:51


    This is a very bad way to write the query. Once you put a scalar UDF,
you are essentially serializing the final output. The function will be
called from every single row. So if it takes 1 ms for one value, if there
are 1000 rows it will take 1 second. This is just the UDF execution.
    Remove the UDF & write a single SELECT statement if you want better
performance & want the optimizer to make better decisions.

--
Umachandar Jayachandran
SQL Resources at http://www.umachandar.com/resources.htm
( Please reply only to newsgroup. )

 
 
 

Select Speed with slow function?

Post by chris harr » Sat, 09 Mar 2002 06:31:59


hi fredrik ,

If you wish to use variables to specify the functions of price and tax,
could you perhaps use a cursor ?  If, as you say, there are many
statements which are complex and different every time, then the cursor
would enable you to work differently with each row returned in the
original result set.

For example ,





declare functioncalculate insensitive cursor for
select product_id from inventory
where product_name = 'Test%'

open functioncalculate


begin






end

close functioncalculate
deallocate functioncalculate

Just a thought, but with many statements being called across what sounds
like many products, a cursor could be very efficient, probably bringing
each call down to less than a second each time because once the query
plans, etc are cached in memory, curosrs can be extremely fast.

Hope this helps anyway.
cheers
chris.

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 13:18:25


I did that in a Stored Proc once, it ended up with a 4 letter pages query.

- Fredrik

Quote:>     This is a very bad way to write the query. Once you put a scalar UDF,
> you are essentially serializing the final output. The function will be
> called from every single row. So if it takes 1 ms for one value, if there
> are 1000 rows it will take 1 second. This is just the UDF execution.
>     Remove the UDF & write a single SELECT statement if you want better
> performance & want the optimizer to make better decisions.

> --
> Umachandar Jayachandran
> SQL Resources at http://www.umachandar.com/resources.htm
> ( Please reply only to newsgroup. )

 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 13:19:57


Here is the UDF if anyone want to take a look at it.

CREATE FUNCTION [dbo].[fnCalculated_Price] (@sProduct_ID as Varchar(30),
@sType as VARCHAR(5) )
RETURNS DECIMAL(18,2) AS
BEGIN
 DECLARE @sManufacturer as VARCHAR(150);
 DECLARE @sGroup_Name_1 as VARCHAR(50);
 DECLARE @sGroup_Name_2 as VARCHAR(50);
 DECLARE @sGroup_Name_3 as VARCHAR(50);

 DECLARE @sField AS VARCHAR(50);
 DECLARE @sValue AS VARCHAR(150);
 DECLARE @sManuf AS VARCHAR(150);
 DECLARE @nUnits AS DECIMAL(18,2);
 DECLARE @nCalculationType AS TINYINT;
 DECLARE @nCalculatedPrice AS DECIMAL(18,2);
 DECLARE @nTestPrice AS DECIMAL(18,2);
 DECLARE @nExitOnHit as TINYINT;

 DECLARE @nPrice_1 as DECIMAL(18,2)
 DECLARE @nPrice_2 as DECIMAL(18,2)
 DECLARE @nCost as DECIMAL(18,2)

SELECT @sManufacturer = MANUFACTURE, @sGroup_Name_1 = GROUP_NAME_1,
@sGroup_Name_2 = GROUP_NAME_2, @sGroup_Name_3 = GROUP_NAME_3, @nCost = COST,
@nPrice_2 = PRICE_2, @nPrice_1 = PRICE_1 FROM INVENTORY (NOLOCK),
INVENTORY_PRICE (NOLOCK) WHERE INVENTORY.PRODUCT_ID =
INVENTORY_PRICE.PRODUCT_ID AND INVENTORY.PRODUCT_ID = @sProduct_ID;

IF @sType = 'A'
BEGIN
 RETURN @nPrice_1
END

IF @sType = 'B'
BEGIN
 RETURN @nPrice_2
END

IF @sType = 'C'
BEGIN
 RETURN @nCost
END

SELECT @nTestPrice = PRICE_1 FROM INVENTORY_FIXED_PRICE (NOLOCK) WHERE
PRODUCT_ID = @sProduct_ID AND CUSTOMER_TYPE = @sType
If @@ROWCOUNT > 0
BEGIN
 RETURN @nTestPrice
END

 SET @nCalculatedPrice = @nPrice_2
 SET @nTestPrice  = @nPrice_2
  DECLARE Cur_1 CURSOR
  FOR
  SELECT FIELD, VALUE, MANUFACTURE, CALCULATION_TYPE, UNITS, EXIT_AFTER_HIT
FROM CUSTOMER_PRICE_RULES (NOLOCK) WHERE TYPE = @sType ORDER BY RULE_ID ASC
        OPEN Cur_1
   FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf, @nCalculationType,
@nUnits, @nExitOnHit
   WHILE (@@FETCH_STATUS <> -1)
   BEGIN
    IF (@@FETCH_STATUS <> -2)
    BEGIN
      IF (( @sField = 'GROUP_NAME_1' AND @sValue = @sGroup_Name_1) OR  (
@sField = 'MANUFACTURE' AND @sValue = @sManufacturer ) OR ( @sField =
'GROUP_NAME_2' AND @sValue = @sGroup_Name_2) OR ( @sField = 'GROUP_NAME_3'
AND @sValue = @sGroup_Name_3) OR ( @sField = 'DEFAULT'))
      BEGIN
     IF @sManuf IS NOT NULL AND @sManuf != ''
     BEGIN
       IF @sManuf = @sManufacturer
       BEGIN
         IF @nCalculationType = 0
       BEGIN
            SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
       END
         IF @nCalculationType = 1
       BEGIN
           SET @nTestPrice = @nCost + @nUnits
       END
       IF @nExitOnHit = 1
       BEGIN
        SET @nCalculatedPrice = @nTestPrice
        RETURN @nCalculatedPrice
        BREAK

       END
       END
     END
     ELSE
     BEGIN
        IF @nCalculationType = 0
      BEGIN
          SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
      END
        IF @nCalculationType = 1
      BEGIN
          SET @nTestPrice = @nCost + @nUnits
      END
      IF @nExitOnHit = 1
      BEGIN
       SET @nCalculatedPrice = @nTestPrice
       RETURN @nCalculatedPrice
       BREAK

      END
     END

      END
    END
   IF @nTestPrice < @nCalculatedPrice
   BEGIN
     SET @nCalculatedPrice = @nTestPrice
   END
   FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf, @nCalculationType,
@nUnits, @nExitOnHit
   END
  CLOSE Cur_1
  DEALLOCATE Cur_1
 RETURN @nCalculatedPrice;
END

"Fredrik Melin" <m...@dacsa.net> wrote in message

news:uifYvUhxBHA.1648@tkmsftngp04...
> Well, the execution plan is nothing more to do about what I can see.
>  The problem is that the function does have to do up to 100 subquery's for
> each row, so that takes time, I have indexes correctly, so its "speeded"
up
> as much as possible.

>   |--Compute

Scalar(DEFINE:([Expr1002]=[dbo].[fnCALCULATED_PRICE](Convert([INVENTORY].[PR
> ODUCT_ID]), 'STA')))
>        |--Index
> Scan(OBJECT:([D1000].[dbo].[INVENTORY].[INVENTORY_WEB_HINT_3]),
> WHERE:([INVENTORY].[GROUP_NAME_1]= 'BILDSK?RMAR'))

> "Reinaldo Kibel (MS)" <reina...@online.microsoft.com> wrote in message
> news:cBInjefxBHA.1876@cpmsftngxa07...
> > Great discussion.
> > Can you check Execution Plan? What does it do when 1 only call to
> > dbo.fnCalcPrice.
> > dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the
index?
> > The WHERE clause is on PRODUCT_NAME. Is there index on both? Check from
> the
> > query plan that the optimizer is using this index.

> > Reinaldo Kibel
> > Microsoft? Corp. - SQL Server Support Engineer

> > This posting is provided "AS IS" with no warranties, and confers no
> rights.

> > Additional support can be obtained at http://support.microsoft.com

> > Are you secure?  For information about the Strategic Technology
Protection
> > Program and to order your FREE Security Tool Kit, please visit
> > http://www.microsoft.com/security.
> > --------------------
> > | From: "Ivan Arjentinski" <jar...@hotmail.com_>
> > | References: <ezxQlyexBHA.1892@tkmsftngp03>
> > | Subject: Re: Select Speed with slow function?
> > | Date: Thu, 7 Mar 2002 18:13:51 +0200
> > | Lines: 65
> > | X-Priority: 3
> > | X-MSMail-Priority: Normal
> > | X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
> > | X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
> > | Message-ID: <O1WYtLfxBHA.1952@tkmsftngp07>
> > | Newsgroups: microsoft.public.sqlserver.programming
> > | NNTP-Posting-Host: 212.91.170.206
> > | Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
> > | Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
> > | X-Tomcat-NG: microsoft.public.sqlserver.programming
> > |
> > | Fredrik,
> > |
> > | Are you sure that the function is executed 2 times? What happens if
you
> > | remove only 1 of the expressions?
> > |
> > | If you are sure that the function is executed 2 times, try this:
> > | SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> > | FROM (
> > |     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> > |     FROM INVENTORY
> > |     WHERE PRODUCT_NAME = 'TEST%'
> > | ) X
> > |
> > | --
> > | Ivan Arjentinski
> > | ----------------------------------------------------------------------
> > | Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> > | scripts), sample data (INSERT INTO....) and desired result set when
> asking
> > | for assistance is highly appreciated
> > | ----------------------------------------------------------------------
> > |
> > | "Fredrik Melin" <m...@dacsa.net> wrote in message
> > | news:ezxQlyexBHA.1892@tkmsftngp03...
> > | > Hi,
> > | >
> > | > I have this select statement (simplified)
> > | >
> > | > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > | > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> > | CUSTOMER_PRICE_WITH_TAX,
> > | > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
> > | >
> > | > Now, this execution takes 16 seconds.
> > | > If I remove one call to dbo.fnCalcPrice the execution takes 9
seconds.
> > | >
> > | > So, each dbo.fnCalcPrice (which itself does serveral selects,
checking
> > | > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > | > Speeding up the function it self any more isnt possible.
> > | >
> > | > Is there anyway to goaround having it to be running 2 times in the
SQL
> > | query
> > | > with changing the clients? (I could do the tax calc on the client
but
> > dont
> > | > want to) and I need the price with and without tax (tax percent is
> > stored
> > | on
> > | > the product).
> > | >
> > | > What I would like (which is not possible) is something like SELECT
> > | @variable
> > | > = dbo.fnCalcPrice(PRODUCT_ID, 'XZY') , @variable AS CUSTOMER_PRICE,
> > | > @variable * TAX_PERCENT as CUSTOMER_PRICE_WITH_TAX, * FROM INVENTORY
> > ....
> > | > But then you get "cannot use variables with data-retrieving
> operation.."
> > | >
> > | > I could wrap everything in a stored procedure, but the where
> statements
> > ar
> > | e
> > | > very complex and diffrent every time..
> > | >
> > | >
> > | >
> > | > Any suggestions how to do the most efficiant query?
> > | >
> > | > - Fredrik
> > | >
> > | >
> > |
> > |
> > |

 
 
 

Select Speed with slow function?

Post by Umachandar Jayachandra » Sat, 09 Mar 2002 14:50:55


    You can use views to simplify lot of the code. If performance is of
importance, then scalar UDFs are not the way to go.

--
Umachandar Jayachandran
SQL Resources at http://www.umachandar.com/resources.htm
( Please reply only to newsgroup. )

 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sat, 09 Mar 2002 15:51:34


Hmm, how could I do to simplify it with views?  look at the function in one
of the other post from me in this thread and please give me suggestions.

One main thing is that this function is live, meaning, its already used in
hundred of places, in many diffrent programs, so changes in each client isnt
something im really too happy about.

- Fredrik


Quote:>     You can use views to simplify lot of the code. If performance is of
> importance, then scalar UDFs are not the way to go.

> --
> Umachandar Jayachandran
> SQL Resources at http://www.umachandar.com/resources.htm
> ( Please reply only to newsgroup. )

 
 
 

Select Speed with slow function?

Post by Luke Amer » Sat, 09 Mar 2002 23:05:11


Hi Fredrik,

I can't be sure, because I don't have your database schema (your table
definitions etc) but I would say that the following query does what your
function does, except it actually uses indexes, unlike the function you
posted that makes heavy use of cursors.

SELECT  PRODUCT_ID,
 CASE @sType
 WHEN 'A' THEN PRICE_1
 WHEN 'B' THEN PRICE_2
 WHEN 'C' THEN COST
 ELSE
  ISNULL(
   (SELECT PRICE_1 FROM INVENTORY_FIXED_PRICE WHERE PRODUCT_ID =
INVENTORY.PRODUCT_ID AND CUSTOMER_TYPE = @sType),
    ISNULL(
     (
     SELECT TOP 1 CASE CALCULATION_TYPE
       WHEN 0 THEN INVENTORY.COST / (1 - (UNITS / 100.0001))
       WHEN 1 THEN INVENTORY.COST + UNITS
       END
     FROM  CUSTOMER_PRICE_RULES
     WHERE  RULE_ID <= ISNULL((SELECT MIN(RULE_ID) FROM CUSTOMER_PRICE_RULES
WHERE TYPE = @sType AND EXIT_AFTER_HIT = 1), RULE_ID) AND
       NOT ((FIELD = 'GROUP_NAME_1' AND VALUE = INVENTORY.GROUP_NAME_1) OR
(FIELD = 'MANUFACTURE' AND VALUE = INVENTORY.MANUFACTURE) OR (FIELD =
'GROUP_NAME_2' AND VALUE = INVENTORY.GROUP_NAME_2) OR (FIELD =
'GROUP_NAME_3' AND VALUE = INVENTORY.GROUP_NAME_3) OR (FIELD = 'DEFAULT'))
       OR (MANUFACTURE IS NOT NULL AND MANUFACTURE != '' AND MANUFACTURE =
INVENTORY.MANUFACTURE)
     ORDER BY RULE_ID
     ),
     INVENTORY.PRICE_2
    )
   )
 END AS PRICE
FROM INVENTORY
WHERE    PRODUCT_ID = @sProductID

It is critical to understand that the use of databases requires following a
set based approached of manipulating data, not an interative approach that
using cursors provides.

I don't mean to be rude, but I think the logic and design of your
application is messed up along with your data model. However, you can use
the query I am posting to speed your function, but even better than that now
with the logic presented as a table you can actually throw away the UDF's
entirely and use the set based nature of the database to return your pricing
in a single SQL statement.

please note again, your logic is quite complicated and I may have missed
something or got something wrong but I think the query will do what your
function was doing.

hope that helps

cheers,
Luke Amery

"Fredrik Melin" <m...@dacsa.net> wrote in message

news:eA88thlxBHA.1740@tkmsftngp04...
> Here is the UDF if anyone want to take a look at it.

> CREATE FUNCTION [dbo].[fnCalculated_Price] (@sProduct_ID as Varchar(30),
> @sType as VARCHAR(5) )
> RETURNS DECIMAL(18,2) AS
> BEGIN
>  DECLARE @sManufacturer as VARCHAR(150);
>  DECLARE @sGroup_Name_1 as VARCHAR(50);
>  DECLARE @sGroup_Name_2 as VARCHAR(50);
>  DECLARE @sGroup_Name_3 as VARCHAR(50);

>  DECLARE @sField AS VARCHAR(50);
>  DECLARE @sValue AS VARCHAR(150);
>  DECLARE @sManuf AS VARCHAR(150);
>  DECLARE @nUnits AS DECIMAL(18,2);
>  DECLARE @nCalculationType AS TINYINT;
>  DECLARE @nCalculatedPrice AS DECIMAL(18,2);
>  DECLARE @nTestPrice AS DECIMAL(18,2);
>  DECLARE @nExitOnHit as TINYINT;

>  DECLARE @nPrice_1 as DECIMAL(18,2)
>  DECLARE @nPrice_2 as DECIMAL(18,2)
>  DECLARE @nCost as DECIMAL(18,2)

> SELECT @sManufacturer = MANUFACTURE, @sGroup_Name_1 = GROUP_NAME_1,
> @sGroup_Name_2 = GROUP_NAME_2, @sGroup_Name_3 = GROUP_NAME_3, @nCost =
COST,
> @nPrice_2 = PRICE_2, @nPrice_1 = PRICE_1 FROM INVENTORY (NOLOCK),
> INVENTORY_PRICE (NOLOCK) WHERE INVENTORY.PRODUCT_ID =
> INVENTORY_PRICE.PRODUCT_ID AND INVENTORY.PRODUCT_ID = @sProduct_ID;

> IF @sType = 'A'
> BEGIN
>  RETURN @nPrice_1
> END

> IF @sType = 'B'
> BEGIN
>  RETURN @nPrice_2
> END

> IF @sType = 'C'
> BEGIN
>  RETURN @nCost
> END

> SELECT @nTestPrice = PRICE_1 FROM INVENTORY_FIXED_PRICE (NOLOCK) WHERE
> PRODUCT_ID = @sProduct_ID AND CUSTOMER_TYPE = @sType
> If @@ROWCOUNT > 0
> BEGIN
>  RETURN @nTestPrice
> END

>  SET @nCalculatedPrice = @nPrice_2
>  SET @nTestPrice  = @nPrice_2
>   DECLARE Cur_1 CURSOR
>   FOR
>   SELECT FIELD, VALUE, MANUFACTURE, CALCULATION_TYPE, UNITS,
EXIT_AFTER_HIT
> FROM CUSTOMER_PRICE_RULES (NOLOCK) WHERE TYPE = @sType ORDER BY RULE_ID
ASC
>         OPEN Cur_1
>    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
@nCalculationType,
> @nUnits, @nExitOnHit
>    WHILE (@@FETCH_STATUS <> -1)
>    BEGIN
>     IF (@@FETCH_STATUS <> -2)
>     BEGIN
>       IF (( @sField = 'GROUP_NAME_1' AND @sValue = @sGroup_Name_1) OR  (
> @sField = 'MANUFACTURE' AND @sValue = @sManufacturer ) OR ( @sField =
> 'GROUP_NAME_2' AND @sValue = @sGroup_Name_2) OR ( @sField = 'GROUP_NAME_3'
> AND @sValue = @sGroup_Name_3) OR ( @sField = 'DEFAULT'))
>       BEGIN
>      IF @sManuf IS NOT NULL AND @sManuf != ''
>      BEGIN
>        IF @sManuf = @sManufacturer
>        BEGIN
>          IF @nCalculationType = 0
>        BEGIN
>             SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
>        END
>          IF @nCalculationType = 1
>        BEGIN
>            SET @nTestPrice = @nCost + @nUnits
>        END
>        IF @nExitOnHit = 1
>        BEGIN
>         SET @nCalculatedPrice = @nTestPrice
>         RETURN @nCalculatedPrice
>         BREAK

>        END
>        END
>      END
>      ELSE
>      BEGIN
>         IF @nCalculationType = 0
>       BEGIN
>           SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
>       END
>         IF @nCalculationType = 1
>       BEGIN
>           SET @nTestPrice = @nCost + @nUnits
>       END
>       IF @nExitOnHit = 1
>       BEGIN
>        SET @nCalculatedPrice = @nTestPrice
>        RETURN @nCalculatedPrice
>        BREAK

>       END
>      END

>       END
>     END
>    IF @nTestPrice < @nCalculatedPrice
>    BEGIN
>      SET @nCalculatedPrice = @nTestPrice
>    END
>    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
@nCalculationType,
> @nUnits, @nExitOnHit
>    END
>   CLOSE Cur_1
>   DEALLOCATE Cur_1
>  RETURN @nCalculatedPrice;
> END

> "Fredrik Melin" <m...@dacsa.net> wrote in message
> news:uifYvUhxBHA.1648@tkmsftngp04...
> > Well, the execution plan is nothing more to do about what I can see.
> >  The problem is that the function does have to do up to 100 subquery's
for
> > each row, so that takes time, I have indexes correctly, so its "speeded"
> up
> > as much as possible.

> >   |--Compute

Scalar(DEFINE:([Expr1002]=[dbo].[fnCALCULATED_PRICE](Convert([INVENTORY].[PR

- Show quoted text -

> > ODUCT_ID]), 'STA')))
> >        |--Index
> > Scan(OBJECT:([D1000].[dbo].[INVENTORY].[INVENTORY_WEB_HINT_3]),
> > WHERE:([INVENTORY].[GROUP_NAME_1]= 'BILDSK?RMAR'))

> > "Reinaldo Kibel (MS)" <reina...@online.microsoft.com> wrote in message
> > news:cBInjefxBHA.1876@cpmsftngxa07...
> > > Great discussion.
> > > Can you check Execution Plan? What does it do when 1 only call to
> > > dbo.fnCalcPrice.
> > > dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the
> index?
> > > The WHERE clause is on PRODUCT_NAME. Is there index on both? Check
from
> > the
> > > query plan that the optimizer is using this index.

> > > Reinaldo Kibel
> > > Microsoft? Corp. - SQL Server Support Engineer

> > > This posting is provided "AS IS" with no warranties, and confers no
> > rights.

> > > Additional support can be obtained at http://support.microsoft.com

> > > Are you secure?  For information about the Strategic Technology
> Protection
> > > Program and to order your FREE Security Tool Kit, please visit
> > > http://www.microsoft.com/security.
> > > --------------------
> > > | From: "Ivan Arjentinski" <jar...@hotmail.com_>
> > > | References: <ezxQlyexBHA.1892@tkmsftngp03>
> > > | Subject: Re: Select Speed with slow function?
> > > | Date: Thu, 7 Mar 2002 18:13:51 +0200
> > > | Lines: 65
> > > | X-Priority: 3
> > > | X-MSMail-Priority: Normal
> > > | X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
> > > | X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
> > > | Message-ID: <O1WYtLfxBHA.1952@tkmsftngp07>
> > > | Newsgroups: microsoft.public.sqlserver.programming
> > > | NNTP-Posting-Host: 212.91.170.206
> > > | Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
> > > | Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
> > > | X-Tomcat-NG: microsoft.public.sqlserver.programming
> > > |
> > > | Fredrik,
> > > |
> > > | Are you sure that the function is executed 2 times? What happens if
> you
> > > | remove only 1 of the expressions?
> > > |
> > > | If you are sure that the function is executed 2 times, try this:
> > > | SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> > > | FROM (
> > > |     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> > > |     FROM INVENTORY
> > > |     WHERE PRODUCT_NAME = 'TEST%'
> > > | ) X
> > > |
> > > | --
> > > | Ivan Arjentinski

| ----------------------------------------------------------------------
> > > | Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> > > | scripts), sample data (INSERT INTO....) and desired result set when
> > asking
> > > | for assistance is highly appreciated

| ----------------------------------------------------------------------

- Show quoted text -

> > > |
> > > | "Fredrik Melin" <m...@dacsa.net> wrote in message
> > > | news:ezxQlyexBHA.1892@tkmsftngp03...
> > > | > Hi,
> > > | >
> > > | > I have this select statement (simplified)
> > > | >
> > > | > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > > | > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> > > | CUSTOMER_PRICE_WITH_TAX,
> > > | > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
> > > | >
> > > | > Now, this execution takes 16 seconds.
> > > | > If I remove one call to dbo.fnCalcPrice the execution takes 9
> seconds.
> > > | >
> > > | > So, each dbo.fnCalcPrice (which itself does serveral selects,
> checking
> > > | > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > > | > Speeding up the function it self any more isnt possible.
> > > | >
> > > | > Is there anyway to goaround having it to be running 2 times in the
> SQL
> > > | query
> > > | > with changing the clients? (I could do the tax calc on the client
> but
> > > dont
> > > | > want to) and I need the price with and without tax (tax

...

read more »

 
 
 

Select Speed with slow function?

Post by Luke Amer » Sat, 09 Mar 2002 23:25:24


sorry, noticed a slight problem after the post, here is the final version:

DECLARE @sType varchar(1)
set @sType = 'A'

SELECT  PRODUCT_ID,
 CASE @sType
 WHEN 'A' THEN PRICE_1
 WHEN 'B' THEN PRICE_2
 WHEN 'C' THEN COST
 ELSE
  ISNULL(
   (SELECT PRICE_1 FROM INVENTORY_FIXED_PRICE WHERE PRODUCT_ID =
INVENTORY.PRODUCT_ID AND CUSTOMER_TYPE = @sType),
    ISNULL(INVENTORY.PRICE_2,
     (
     SELECT  CASE CALCULATION_TYPE
       WHEN 0 THEN INVENTORY.COST / (1 - (UNITS / 100.0001))
       WHEN 1 THEN INVENTORY.COST + UNITS
       END
     FROM  CUSTOMER_PRICE_RULES
     WHERE  RULE_ID = ISNULL((SELECT MIN(RULE_ID) FROM CUSTOMER_PRICE_RULES
WHERE TYPE = @sType AND EXIT_AFTER_HIT = 1), (SELECT MAX(RULE_ID) FROM
CUSTOMER_PRICE_RULES WHERE TYPE = @sType)) AND
       NOT ((FIELD = 'GROUP_NAME_1' AND VALUE = INVENTORY.GROUP_NAME_1) OR
(FIELD = 'MANUFACTURE' AND VALUE = INVENTORY.MANUFACTURE) OR (FIELD =
'GROUP_NAME_2' AND VALUE = INVENTORY.GROUP_NAME_2) OR (FIELD =
'GROUP_NAME_3' AND VALUE = INVENTORY.GROUP_NAME_3) OR (FIELD = 'DEFAULT'))
       OR (MANUFACTURE IS NOT NULL AND MANUFACTURE != '' AND MANUFACTURE =
INVENTORY.MANUFACTURE)
     )
    )
   )
 END AS PRICE
FROM INVENTORY
WHERE PRODUCT_ID = @sProductID

"Fredrik Melin" <m...@dacsa.net> wrote in message

news:eA88thlxBHA.1740@tkmsftngp04...
> Here is the UDF if anyone want to take a look at it.

> CREATE FUNCTION [dbo].[fnCalculated_Price] (@sProduct_ID as Varchar(30),
> @sType as VARCHAR(5) )
> RETURNS DECIMAL(18,2) AS
> BEGIN
>  DECLARE @sManufacturer as VARCHAR(150);
>  DECLARE @sGroup_Name_1 as VARCHAR(50);
>  DECLARE @sGroup_Name_2 as VARCHAR(50);
>  DECLARE @sGroup_Name_3 as VARCHAR(50);

>  DECLARE @sField AS VARCHAR(50);
>  DECLARE @sValue AS VARCHAR(150);
>  DECLARE @sManuf AS VARCHAR(150);
>  DECLARE @nUnits AS DECIMAL(18,2);
>  DECLARE @nCalculationType AS TINYINT;
>  DECLARE @nCalculatedPrice AS DECIMAL(18,2);
>  DECLARE @nTestPrice AS DECIMAL(18,2);
>  DECLARE @nExitOnHit as TINYINT;

>  DECLARE @nPrice_1 as DECIMAL(18,2)
>  DECLARE @nPrice_2 as DECIMAL(18,2)
>  DECLARE @nCost as DECIMAL(18,2)

> SELECT @sManufacturer = MANUFACTURE, @sGroup_Name_1 = GROUP_NAME_1,
> @sGroup_Name_2 = GROUP_NAME_2, @sGroup_Name_3 = GROUP_NAME_3, @nCost =
COST,
> @nPrice_2 = PRICE_2, @nPrice_1 = PRICE_1 FROM INVENTORY (NOLOCK),
> INVENTORY_PRICE (NOLOCK) WHERE INVENTORY.PRODUCT_ID =
> INVENTORY_PRICE.PRODUCT_ID AND INVENTORY.PRODUCT_ID = @sProduct_ID;

> IF @sType = 'A'
> BEGIN
>  RETURN @nPrice_1
> END

> IF @sType = 'B'
> BEGIN
>  RETURN @nPrice_2
> END

> IF @sType = 'C'
> BEGIN
>  RETURN @nCost
> END

> SELECT @nTestPrice = PRICE_1 FROM INVENTORY_FIXED_PRICE (NOLOCK) WHERE
> PRODUCT_ID = @sProduct_ID AND CUSTOMER_TYPE = @sType
> If @@ROWCOUNT > 0
> BEGIN
>  RETURN @nTestPrice
> END

>  SET @nCalculatedPrice = @nPrice_2
>  SET @nTestPrice  = @nPrice_2
>   DECLARE Cur_1 CURSOR
>   FOR
>   SELECT FIELD, VALUE, MANUFACTURE, CALCULATION_TYPE, UNITS,
EXIT_AFTER_HIT
> FROM CUSTOMER_PRICE_RULES (NOLOCK) WHERE TYPE = @sType ORDER BY RULE_ID
ASC
>         OPEN Cur_1
>    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
@nCalculationType,
> @nUnits, @nExitOnHit
>    WHILE (@@FETCH_STATUS <> -1)
>    BEGIN
>     IF (@@FETCH_STATUS <> -2)
>     BEGIN
>       IF (( @sField = 'GROUP_NAME_1' AND @sValue = @sGroup_Name_1) OR  (
> @sField = 'MANUFACTURE' AND @sValue = @sManufacturer ) OR ( @sField =
> 'GROUP_NAME_2' AND @sValue = @sGroup_Name_2) OR ( @sField = 'GROUP_NAME_3'
> AND @sValue = @sGroup_Name_3) OR ( @sField = 'DEFAULT'))
>       BEGIN
>      IF @sManuf IS NOT NULL AND @sManuf != ''
>      BEGIN
>        IF @sManuf = @sManufacturer
>        BEGIN
>          IF @nCalculationType = 0
>        BEGIN
>             SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
>        END
>          IF @nCalculationType = 1
>        BEGIN
>            SET @nTestPrice = @nCost + @nUnits
>        END
>        IF @nExitOnHit = 1
>        BEGIN
>         SET @nCalculatedPrice = @nTestPrice
>         RETURN @nCalculatedPrice
>         BREAK

>        END
>        END
>      END
>      ELSE
>      BEGIN
>         IF @nCalculationType = 0
>       BEGIN
>           SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
>       END
>         IF @nCalculationType = 1
>       BEGIN
>           SET @nTestPrice = @nCost + @nUnits
>       END
>       IF @nExitOnHit = 1
>       BEGIN
>        SET @nCalculatedPrice = @nTestPrice
>        RETURN @nCalculatedPrice
>        BREAK

>       END
>      END

>       END
>     END
>    IF @nTestPrice < @nCalculatedPrice
>    BEGIN
>      SET @nCalculatedPrice = @nTestPrice
>    END
>    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
@nCalculationType,
> @nUnits, @nExitOnHit
>    END
>   CLOSE Cur_1
>   DEALLOCATE Cur_1
>  RETURN @nCalculatedPrice;
> END

> "Fredrik Melin" <m...@dacsa.net> wrote in message
> news:uifYvUhxBHA.1648@tkmsftngp04...
> > Well, the execution plan is nothing more to do about what I can see.
> >  The problem is that the function does have to do up to 100 subquery's
for
> > each row, so that takes time, I have indexes correctly, so its "speeded"
> up
> > as much as possible.

> >   |--Compute

Scalar(DEFINE:([Expr1002]=[dbo].[fnCALCULATED_PRICE](Convert([INVENTORY].[PR

- Show quoted text -

> > ODUCT_ID]), 'STA')))
> >        |--Index
> > Scan(OBJECT:([D1000].[dbo].[INVENTORY].[INVENTORY_WEB_HINT_3]),
> > WHERE:([INVENTORY].[GROUP_NAME_1]= 'BILDSK?RMAR'))

> > "Reinaldo Kibel (MS)" <reina...@online.microsoft.com> wrote in message
> > news:cBInjefxBHA.1876@cpmsftngxa07...
> > > Great discussion.
> > > Can you check Execution Plan? What does it do when 1 only call to
> > > dbo.fnCalcPrice.
> > > dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the
> index?
> > > The WHERE clause is on PRODUCT_NAME. Is there index on both? Check
from
> > the
> > > query plan that the optimizer is using this index.

> > > Reinaldo Kibel
> > > Microsoft? Corp. - SQL Server Support Engineer

> > > This posting is provided "AS IS" with no warranties, and confers no
> > rights.

> > > Additional support can be obtained at http://support.microsoft.com

> > > Are you secure?  For information about the Strategic Technology
> Protection
> > > Program and to order your FREE Security Tool Kit, please visit
> > > http://www.microsoft.com/security.
> > > --------------------
> > > | From: "Ivan Arjentinski" <jar...@hotmail.com_>
> > > | References: <ezxQlyexBHA.1892@tkmsftngp03>
> > > | Subject: Re: Select Speed with slow function?
> > > | Date: Thu, 7 Mar 2002 18:13:51 +0200
> > > | Lines: 65
> > > | X-Priority: 3
> > > | X-MSMail-Priority: Normal
> > > | X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
> > > | X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
> > > | Message-ID: <O1WYtLfxBHA.1952@tkmsftngp07>
> > > | Newsgroups: microsoft.public.sqlserver.programming
> > > | NNTP-Posting-Host: 212.91.170.206
> > > | Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
> > > | Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
> > > | X-Tomcat-NG: microsoft.public.sqlserver.programming
> > > |
> > > | Fredrik,
> > > |
> > > | Are you sure that the function is executed 2 times? What happens if
> you
> > > | remove only 1 of the expressions?
> > > |
> > > | If you are sure that the function is executed 2 times, try this:
> > > | SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> > > | FROM (
> > > |     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> > > |     FROM INVENTORY
> > > |     WHERE PRODUCT_NAME = 'TEST%'
> > > | ) X
> > > |
> > > | --
> > > | Ivan Arjentinski

| ----------------------------------------------------------------------
> > > | Please reply to newsgroups. Inclusion of table schemas (CREATE TABLE
> > > | scripts), sample data (INSERT INTO....) and desired result set when
> > asking
> > > | for assistance is highly appreciated

| ----------------------------------------------------------------------

- Show quoted text -

> > > |
> > > | "Fredrik Melin" <m...@dacsa.net> wrote in message
> > > | news:ezxQlyexBHA.1892@tkmsftngp03...
> > > | > Hi,
> > > | >
> > > | > I have this select statement (simplified)
> > > | >
> > > | > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > > | > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> > > | CUSTOMER_PRICE_WITH_TAX,
> > > | > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
> > > | >
> > > | > Now, this execution takes 16 seconds.
> > > | > If I remove one call to dbo.fnCalcPrice the execution takes 9
> seconds.
> > > | >
> > > | > So, each dbo.fnCalcPrice (which itself does serveral selects,
> checking
> > > | > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > > | > Speeding up the function it self any more isnt possible.
> > > | >
> > > | > Is there anyway to goaround having it to be running 2 times in the
> SQL
> > > | query
> > > | > with changing the clients? (I could do the tax calc on the client
> but
> > > dont
> > > | > want to) and I need the price with and without tax (tax percent is
> > > stored
> > > | on
> > > | > the product).
> > > | >
> > > | > What I would like (which is not possible) is something like SELECT
> > > | @variable
> > > | > = dbo.fnCalcPrice(PRODUCT_ID, 'XZY') , @variable AS
CUSTOMER_PRICE,
> > > | > @variable * TAX_PERCENT as CUSTOMER_PRICE_WITH_TAX, * FROM
INVENTORY
> > > ....
> > > | > But then you get "cannot use variables with data-retrieving
> > operation.."
> > > | >
> > > | > I could wrap everything in a stored procedure, but the where
> > statements
> > > ar
> > > | e
> > > | > very complex and diffrent every time..
> > > | >
> > > | >
> > > | >
> > > | > Any suggestions how to do the most efficiant query?
> > > | >
> > > | > - Fredrik
> > > | >
> > > | >
> > > |
> > > |
> > > |

 
 
 

Select Speed with slow function?

Post by Fredrik Meli » Sun, 10 Mar 2002 00:02:46


Perfect!

THANK YOU LUKE!!

/hat off, bow

"Luke Amery" <lukeam...@hotmail.com> wrote in message

news:e0lNj3qxBHA.1396@tkmsftngp05...
> sorry, noticed a slight problem after the post, here is the final version:

> DECLARE @sType varchar(1)
> set @sType = 'A'

> SELECT  PRODUCT_ID,
>  CASE @sType
>  WHEN 'A' THEN PRICE_1
>  WHEN 'B' THEN PRICE_2
>  WHEN 'C' THEN COST
>  ELSE
>   ISNULL(
>    (SELECT PRICE_1 FROM INVENTORY_FIXED_PRICE WHERE PRODUCT_ID =
> INVENTORY.PRODUCT_ID AND CUSTOMER_TYPE = @sType),
>     ISNULL(INVENTORY.PRICE_2,
>      (
>      SELECT  CASE CALCULATION_TYPE
>        WHEN 0 THEN INVENTORY.COST / (1 - (UNITS / 100.0001))
>        WHEN 1 THEN INVENTORY.COST + UNITS
>        END
>      FROM  CUSTOMER_PRICE_RULES
>      WHERE  RULE_ID = ISNULL((SELECT MIN(RULE_ID) FROM

CUSTOMER_PRICE_RULES

- Show quoted text -

> WHERE TYPE = @sType AND EXIT_AFTER_HIT = 1), (SELECT MAX(RULE_ID) FROM
> CUSTOMER_PRICE_RULES WHERE TYPE = @sType)) AND
>        NOT ((FIELD = 'GROUP_NAME_1' AND VALUE = INVENTORY.GROUP_NAME_1) OR
> (FIELD = 'MANUFACTURE' AND VALUE = INVENTORY.MANUFACTURE) OR (FIELD =
> 'GROUP_NAME_2' AND VALUE = INVENTORY.GROUP_NAME_2) OR (FIELD =
> 'GROUP_NAME_3' AND VALUE = INVENTORY.GROUP_NAME_3) OR (FIELD = 'DEFAULT'))
>        OR (MANUFACTURE IS NOT NULL AND MANUFACTURE != '' AND MANUFACTURE =
> INVENTORY.MANUFACTURE)
>      )
>     )
>    )
>  END AS PRICE
> FROM INVENTORY
> WHERE PRODUCT_ID = @sProductID

> "Fredrik Melin" <m...@dacsa.net> wrote in message
> news:eA88thlxBHA.1740@tkmsftngp04...
> > Here is the UDF if anyone want to take a look at it.

> > CREATE FUNCTION [dbo].[fnCalculated_Price] (@sProduct_ID as Varchar(30),
> > @sType as VARCHAR(5) )
> > RETURNS DECIMAL(18,2) AS
> > BEGIN
> >  DECLARE @sManufacturer as VARCHAR(150);
> >  DECLARE @sGroup_Name_1 as VARCHAR(50);
> >  DECLARE @sGroup_Name_2 as VARCHAR(50);
> >  DECLARE @sGroup_Name_3 as VARCHAR(50);

> >  DECLARE @sField AS VARCHAR(50);
> >  DECLARE @sValue AS VARCHAR(150);
> >  DECLARE @sManuf AS VARCHAR(150);
> >  DECLARE @nUnits AS DECIMAL(18,2);
> >  DECLARE @nCalculationType AS TINYINT;
> >  DECLARE @nCalculatedPrice AS DECIMAL(18,2);
> >  DECLARE @nTestPrice AS DECIMAL(18,2);
> >  DECLARE @nExitOnHit as TINYINT;

> >  DECLARE @nPrice_1 as DECIMAL(18,2)
> >  DECLARE @nPrice_2 as DECIMAL(18,2)
> >  DECLARE @nCost as DECIMAL(18,2)

> > SELECT @sManufacturer = MANUFACTURE, @sGroup_Name_1 = GROUP_NAME_1,
> > @sGroup_Name_2 = GROUP_NAME_2, @sGroup_Name_3 = GROUP_NAME_3, @nCost =
> COST,
> > @nPrice_2 = PRICE_2, @nPrice_1 = PRICE_1 FROM INVENTORY (NOLOCK),
> > INVENTORY_PRICE (NOLOCK) WHERE INVENTORY.PRODUCT_ID =
> > INVENTORY_PRICE.PRODUCT_ID AND INVENTORY.PRODUCT_ID = @sProduct_ID;

> > IF @sType = 'A'
> > BEGIN
> >  RETURN @nPrice_1
> > END

> > IF @sType = 'B'
> > BEGIN
> >  RETURN @nPrice_2
> > END

> > IF @sType = 'C'
> > BEGIN
> >  RETURN @nCost
> > END

> > SELECT @nTestPrice = PRICE_1 FROM INVENTORY_FIXED_PRICE (NOLOCK) WHERE
> > PRODUCT_ID = @sProduct_ID AND CUSTOMER_TYPE = @sType
> > If @@ROWCOUNT > 0
> > BEGIN
> >  RETURN @nTestPrice
> > END

> >  SET @nCalculatedPrice = @nPrice_2
> >  SET @nTestPrice  = @nPrice_2
> >   DECLARE Cur_1 CURSOR
> >   FOR
> >   SELECT FIELD, VALUE, MANUFACTURE, CALCULATION_TYPE, UNITS,
> EXIT_AFTER_HIT
> > FROM CUSTOMER_PRICE_RULES (NOLOCK) WHERE TYPE = @sType ORDER BY RULE_ID
> ASC
> >         OPEN Cur_1
> >    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
> @nCalculationType,
> > @nUnits, @nExitOnHit
> >    WHILE (@@FETCH_STATUS <> -1)
> >    BEGIN
> >     IF (@@FETCH_STATUS <> -2)
> >     BEGIN
> >       IF (( @sField = 'GROUP_NAME_1' AND @sValue = @sGroup_Name_1) OR  (
> > @sField = 'MANUFACTURE' AND @sValue = @sManufacturer ) OR ( @sField =
> > 'GROUP_NAME_2' AND @sValue = @sGroup_Name_2) OR ( @sField =
'GROUP_NAME_3'
> > AND @sValue = @sGroup_Name_3) OR ( @sField = 'DEFAULT'))
> >       BEGIN
> >      IF @sManuf IS NOT NULL AND @sManuf != ''
> >      BEGIN
> >        IF @sManuf = @sManufacturer
> >        BEGIN
> >          IF @nCalculationType = 0
> >        BEGIN
> >             SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
> >        END
> >          IF @nCalculationType = 1
> >        BEGIN
> >            SET @nTestPrice = @nCost + @nUnits
> >        END
> >        IF @nExitOnHit = 1
> >        BEGIN
> >         SET @nCalculatedPrice = @nTestPrice
> >         RETURN @nCalculatedPrice
> >         BREAK

> >        END
> >        END
> >      END
> >      ELSE
> >      BEGIN
> >         IF @nCalculationType = 0
> >       BEGIN
> >           SET @nTestPrice = ( @nCost / (1- (@nUnits /100.0001)))
> >       END
> >         IF @nCalculationType = 1
> >       BEGIN
> >           SET @nTestPrice = @nCost + @nUnits
> >       END
> >       IF @nExitOnHit = 1
> >       BEGIN
> >        SET @nCalculatedPrice = @nTestPrice
> >        RETURN @nCalculatedPrice
> >        BREAK

> >       END
> >      END

> >       END
> >     END
> >    IF @nTestPrice < @nCalculatedPrice
> >    BEGIN
> >      SET @nCalculatedPrice = @nTestPrice
> >    END
> >    FETCH NEXT FROM Cur_1 INTO @sField, @sValue, @sManuf,
> @nCalculationType,
> > @nUnits, @nExitOnHit
> >    END
> >   CLOSE Cur_1
> >   DEALLOCATE Cur_1
> >  RETURN @nCalculatedPrice;
> > END

> > "Fredrik Melin" <m...@dacsa.net> wrote in message
> > news:uifYvUhxBHA.1648@tkmsftngp04...
> > > Well, the execution plan is nothing more to do about what I can see.
> > >  The problem is that the function does have to do up to 100 subquery's
> for
> > > each row, so that takes time, I have indexes correctly, so its
"speeded"
> > up
> > > as much as possible.

> > >   |--Compute

Scalar(DEFINE:([Expr1002]=[dbo].[fnCALCULATED_PRICE](Convert([INVENTORY].[PR

- Show quoted text -

> > > ODUCT_ID]), 'STA')))
> > >        |--Index
> > > Scan(OBJECT:([D1000].[dbo].[INVENTORY].[INVENTORY_WEB_HINT_3]),
> > > WHERE:([INVENTORY].[GROUP_NAME_1]= 'BILDSK?RMAR'))

> > > "Reinaldo Kibel (MS)" <reina...@online.microsoft.com> wrote in message
> > > news:cBInjefxBHA.1876@cpmsftngxa07...
> > > > Great discussion.
> > > > Can you check Execution Plan? What does it do when 1 only call to
> > > > dbo.fnCalcPrice.
> > > > dbo.fnCalcPrice uses  PRODUC_ID as a parameter. Is this part of the
> > index?
> > > > The WHERE clause is on PRODUCT_NAME. Is there index on both? Check
> from
> > > the
> > > > query plan that the optimizer is using this index.

> > > > Reinaldo Kibel
> > > > Microsoft? Corp. - SQL Server Support Engineer

> > > > This posting is provided "AS IS" with no warranties, and confers no
> > > rights.

> > > > Additional support can be obtained at http://support.microsoft.com

> > > > Are you secure?  For information about the Strategic Technology
> > Protection
> > > > Program and to order your FREE Security Tool Kit, please visit
> > > > http://www.microsoft.com/security.
> > > > --------------------
> > > > | From: "Ivan Arjentinski" <jar...@hotmail.com_>
> > > > | References: <ezxQlyexBHA.1892@tkmsftngp03>
> > > > | Subject: Re: Select Speed with slow function?
> > > > | Date: Thu, 7 Mar 2002 18:13:51 +0200
> > > > | Lines: 65
> > > > | X-Priority: 3
> > > > | X-MSMail-Priority: Normal
> > > > | X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
> > > > | X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
> > > > | Message-ID: <O1WYtLfxBHA.1952@tkmsftngp07>
> > > > | Newsgroups: microsoft.public.sqlserver.programming
> > > > | NNTP-Posting-Host: 212.91.170.206
> > > > | Path: cpmsftngxa07!tkmsftngp01!tkmsftngp07
> > > > | Xref: cpmsftngxa07 microsoft.public.sqlserver.programming:238681
> > > > | X-Tomcat-NG: microsoft.public.sqlserver.programming
> > > > |
> > > > | Fredrik,
> > > > |
> > > > | Are you sure that the function is executed 2 times? What happens
if
> > you
> > > > | remove only 1 of the expressions?
> > > > |
> > > > | If you are sure that the function is executed 2 times, try this:
> > > > | SELECT Customer_Price * Tax_Percent AS Customer_Price_With_Tax, *
> > > > | FROM (
> > > > |     SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,*
> > > > |     FROM INVENTORY
> > > > |     WHERE PRODUCT_NAME = 'TEST%'
> > > > | ) X
> > > > |
> > > > | --
> > > > | Ivan Arjentinski

> | ----------------------------------------------------------------------
> > > > | Please reply to newsgroups. Inclusion of table schemas (CREATE
TABLE
> > > > | scripts), sample data (INSERT INTO....) and desired result set
when
> > > asking
> > > > | for assistance is highly appreciated

> | ----------------------------------------------------------------------
> > > > |
> > > > | "Fredrik Melin" <m...@dacsa.net> wrote in message
> > > > | news:ezxQlyexBHA.1892@tkmsftngp03...
> > > > | > Hi,
> > > > | >
> > > > | > I have this select statement (simplified)
> > > > | >
> > > > | > SELECT dbo.fnCalcPrice(PRODUC_ID, 'XZY') AS CUSTOMER_PRICE,
> > > > | > dbo.fnCalcPrice(PRODUC_ID, 'XZY') * TAX_PERCENT AS
> > > > | CUSTOMER_PRICE_WITH_TAX,
> > > > | > * FROM INVENTORY WHERE PRODUCT_NAME = 'TEST%'
> > > > | >
> > > > | > Now, this execution takes 16 seconds.
> > > > | > If I remove one call to dbo.fnCalcPrice the execution takes 9
> > seconds.
> > > > | >
> > > > | > So, each dbo.fnCalcPrice (which itself does serveral selects,
> > checking
> > > > | > prices, depending on type (xyz) etc ) takes about 7 seconds.
> > > > | > Speeding up the function it self any more isnt possible.
> > > > | >
> > > > | > Is there anyway to goaround having it to be running 2 times in
the
> > SQL
> > > > | query
> > > > | > with changing the clients? (I could do the tax calc on the
client
> > but
> > > > dont
> > > > | > want to) and I need the price with and without tax (tax percent
is
> > > > stored
> > > > | on
> > > > | > the product).
> > > > | >
> > > > | > What I would like (which is not possible) is something like
SELECT
> > > > | @variable
> > > > | > =

...

read more »