Help On StoredProc....Running for more than 2 minutes

  • Hello I need help on this StoredProc

    It has been running for like more than a minute

    I want to performance tune it to run for seconds any help will be appreciated

    USE [prdlcon]

    GO

    /****** Object: StoredProcedure [dbo].[upr_MaintenanceSpendByManuByDate] Script Date: 11/11/2011 09:43:50 ******/

    SET ANSI_NULLS OFF

    GO

    SET QUOTED_IDENTIFIER OFF

    GO

    /**********************************************************************************************

    -- USE LCON

    -- Swan AUR228 for Joe Bhamra 26/03/2008

    -- Requires new some new fields added to the following report - Reporter > ServiceTrak > Maintenance Spend by Manufacturer by date

    -- add model(of vehicle). Currently column (F) - Maintspend - can this be split into Parts and Labour for the invoice.

    **********************************************************************************************/

    --ALTER Procedure [dbo].[upr_MaintenanceSpendByManuByDate]

    declare @dbPrefix varchar(3) = 'PRD', @StartDate varchar(10) = '2011/10/01', @EndDate varchar(10)= '2011/10/10', @Mfr varchar(8) = 'FO', @LiveVehicles varchar(1) = 'y' -- AS

    DECLARE @sqlstring NVARCHAR(4000)

    SELECT SUBSTRING(v.description,1,2) AS Manufacturer,

    mo.model_name AS Model,

    ih.supp_acc_no AS Supp_Acc_No, tp.[name] AS Supplier_Name,

    prdtprt.dbo.GetCity(addr1,addr2,addr3,addr4,addr5),

    CONVERT(VARCHAR,ih.created_on,111) AS Created_On,

    SUM(prdlcon.dbo.GetMaintSpendByDate(ch.vehicle_id, @StartDate, @EndDate, ih.invoice_header_id)) AS Maintenance_Spend,

    SUM(prdlcon.dbo.GetPartsCost(ch.vehicle_id, @StartDate, @EndDate, ih.invoice_header_id)) AS Parts,

    SUM(prdlcon.dbo.GetLabourCost(ch.vehicle_id, @StartDate, @EndDate, ih.invoice_header_id)) AS Labour,

    prdtprt.dbo.GetGarageFranchises(ih.supp_acc_no) AS Franchises, v.vehicle_reg, oh.supp_labour_rate, ch.fleet,

    prdtprt.dbo.GetFleetName (ch.fleet) AS Fleet_Name,

    (CASE ga.service_trak_flag when 1 then 'YES' else 'NO' END) as Service_trak,

    (CASE ga.preferred when 1 then 'YES' else 'NO' end) as Preferred,

    a.bacs_discount *100,

    Prdtprt.dbo.GetFranchisePartsDiscount(tp.trading_partner_id,getdate()) *100,

    op.description,

    op.quantity,

    op.unit_price,

    op.disc_unit_price,

    op.net_parts_price

    FROM

    contract_history ch

    INNER JOIN vehicles v ON v.contract_id = ch.contract_id and v.vehicle_id = ch.vehicle_id

    INNER JOIN invoice_headers ih ON ih.vehicle_id = ch.vehicle_id

    INNER JOIN order_headers oh ON oh.order_header_id = ih.order_header_id and oh.vehicle_id = ih.vehicle_id

    INNER JOIN prdtprt.dbo.accnt_details a ON account_no = oh.supp_account

    INNER JOIN prdtprt.dbo.tp_contact tpc ON tpc.trading_partner_id = a.trading_partner_id and tpc.contact_role_id =1

    INNER JOIN prdtprt.dbo.address addr ON addr.address_id = tpc.address_id

    INNER JOIN prdtprt.dbo.trading_partner tp ON tp.trading_partner_id = tpc.trading_partner_id

    LEFT OUTER JOIN prdvmnt.dbo.variants [var] ON v.david_henley_id = [var].dhs_id COLLATE Latin1_General_CI_AS

    LEFT OUTER JOIN prdvmnt.dbo.models mo ON [var].manufacturer_id = mo.manufacturer_id and VAR.model_id = mo.model_id

    LEFT OUTER JOIN prdtprt.dbo.garages ga ON tp.trading_partner_id = ga.trading_partner_id

    and ga.GARAGE_ID = (select MIN(garage_id) from prdtprt.dbo.garages ga2 where ga2.TRADING_PARTNER_ID = ga.TRADING_PARTNER_ID)

    LEFT OUTER JOIN order_parts op on op.vehicle_id = oh.vehicle_id -- and op.order_header_id = oh.order_header_id and (op.description like '%synth%' or op.description like '%min%')

    WHERE ih.created_on BETWEEN CAST(@StartDate AS DATETIME) AND CAST(@EndDate AS DATETIME)

    AND (@Mfr ='' OR (SUBSTRING(@Mfr,1,2) =SUBSTRING(v.[description],1,2)))

    AND ((ch.[to] IS NULL AND @LiveVehicles = 'Y') OR @LiveVehicles = 'A')

    GROUP BY

    SUBSTRING(v.[description],1,2),

    ih.supp_acc_no, tp.[name], prdtprt.dbo.GetCity(addr1,addr2,addr3,addr4,addr5),

    CONVERT(VARCHAR,ih.created_on,111),

    prdtprt.dbo.GetGarageFranchises(ih.supp_acc_no), v.vehicle_reg, oh.supp_labour_rate, ch.fleet,

    prdtprt.dbo.GetFleetName (ch.fleet),

    mo.model_name, ch.vehicle_id, ih.created_on, ih.order_header_id, ga.service_trak_flag, ga.preferred,a.bacs_discount *100,

    Prdtprt.dbo.GetFranchisePartsDiscount(tp.trading_partner_id,getdate()) *100,

    op.description,

    op.quantity,

    op.unit_price,

    op.disc_unit_price,

    op.net_parts_price

    HAVING

    sum(prdlcon.dbo.GetMaintSpendByDate(ch.vehicle_id, @StartDate , @EndDate , ih.invoice_header_id)) <> 0

    ORDER BY 1,2,3,11

    --execute sp_executesql @sqlstring

    --print @sqlstring

    Regards

  • Two things you might consider are converting your scalar-value "Get" functions to table-value functions, and omitting the ORDER BY and having your presentation layer do the sorting instead.

    John

  • Please share the execution plan of stored procedure.

  • There are seven functions in your output list. Guessing from the function names and the passed parameters, a couple of them perform quite complex calculations touching several tables. Your first step should be to evaluate how much each one costs to run, then determine if it's worth rewriting the logic into your code instead of using the function. Since you're using SS2K8 you can probably incorporate those functions with minimal change into your FROM list as CROSS/OUTER APPLY which would make this rewriting much easier.

    So, comment out all of the functions in the SELECT list. Run the query a couple of times and time how long it takes. Better still, SET STATISTICS TIME ON. Then uncomment the first function and repeat, then the second and so on - uncommenting one function at a time.

    There's some scope for performance tweaking in the rest of the query too.

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Please post table definitions, index definitions and execution plan, as per http://qa.sqlservercentral.com/articles/SQLServerCentral/66909/

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • PLEASE DONT MIND THE FAINT NATURE

    THE EXECUTION PLAN IS ATTACHED

    THANKS FOR UR HELP

  • pespes009 (11/11/2011)


    PLEASE DONT MIND THE FAINT NATURE

    THE EXECUTION PLAN IS ATTACHED

    THANKS FOR UR HELP

    We need the .sqlplan file. We can't do anything with that jpeg.

    P.S. posting in all caps = shouting and is usually not welcomed on forums ;-).

  • HERE IT IS

  • pespes009 (11/11/2011)


    HERE IT IS

    All capitals letters = shouting. Please stop it.

    Thanks in advance.

  • o sorry

  • Great, one of three.

    Table definitions please

    Index definitions please (both as CREATE statements, not pictures)

    Edit: Also the definition of the user defined functions please. It's very likely that they are a large part of the problem.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • pespes009 (11/11/2011)


    o sorry

    No problem.

    You have no less than 12 objects scans. You also have functions that possibly also do table scans.

    There's no 2 minute solution I can give you for this. I'd need full access to the system to start working on it.

    What I'd try here is to remove the functions to see how much gains that gets me. If it's massive I'd consider divide and conquer. That means intermediate temp table to save the results.

    I'd probably do the same on the base tables that will have the greatest filter impact.

    Then finalize with all the joins. That's the best chance you have to get seeks somewhere.

    The plan is not noting any missing indexes and there's no compile timeout... so again, nothing obvious.

    This is easily a 1-2 days job depending on how fast you need this to run.

  • One thing straight off...

    Why are you declaring your dates as strings

    @StartDate varchar(10) = '2011/10/01', @EndDate varchar(10)= '2011/10/10'

    and then converting them to datetime

    CAST(@StartDate AS DATETIME) AND CAST(@EndDate AS DATETIME)

    That's just a waste of processing time

    Also:

    ORDER BY 1,2,3,11

    Column names, rather than ordinal positions are easier to read and less likely to be broken by a minor change to the select.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass

Viewing 13 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic. Login to reply