Search code examples
sql-serversql-server-2008t-sqlquery-optimization

Need to reduce Query Time


My problem is below query takes 38 seconds to complete, I need to reduce this time as much as I can. When I look at Execution plan : %54 cost spend on Dim_Customers Index Scanning. Any suggestion would be appreciated. Thanks

DECLARE @SalesPersonCode NVARCHAR(4)
DECLARE @StartDate       DATETIME
DECLARE @EndDate         DATETIME

SET @SalesPersonCode = 'AC';
SET @StartDate       = '03/01/2012';
SET @endDate         = '03/31/2012';

SELECT AA_FactSalesOrderDetails.Salesperson
             , Dim_SalesOrganisation.[Salesperson name]
             , AA_FactSalesOrderDetails.[Order Date]
             , Dim_Customers.[Customer number]
             , Dim_Customers.[Customer name]
             , Dim_Customers.[Area/state]
             , Dim_Customers.country
             , Dim_Customers.[Customer stop] AS [Customer Block]
             , AA_FactSalesOrderDetails.[Customer order stop] AS [Co Stop]
             , AA_FactSalesOrderDetails.[First delivery date Header]
             , AA_FactSalesOrderDetails.[Last delivery date Header]
             , Dim_Customers.[User-defined field 6 - customer]
             , Dim_Customers.[Customer group name]
             , AA_FactSalesOrderDetails.[Contact Method]
             , AA_FactSalesOrderDetails.[Customer order number]
             , AA_FactSalesOrderDetails.[Price Level]
             , AA_FactSalesOrderDetails.[Item number]
             , Dim_Items.[Product group description]  AS [Item name]
             , AA_FactSalesOrderDetails.[Ordered quantity - basic U/M] AS [Quantity Ordered]
             , AA_FactSalesOrderDetails.[Ordered quantity - basic U/M] * AA_FactSalesOrderDetails.[Net price] AS [Order Line Total ]

FROM AA_FactSalesOrderDetails 
     LEFT JOIN
     Dim_SalesOrganisation
     ON
     AA_FactSalesOrderDetails.Salesperson = Dim_SalesOrganisation.Salesperson
     LEFT JOIN
     Dim_Customers
     ON
     AA_FactSalesOrderDetails.Dim_Customers_dKey = Dim_Customers.Dim_Customers_dKey
     LEFT JOIN
     Dim_Items
     ON
     AA_FactSalesOrderDetails.[Item number] = Dim_Items.[Item number]
     LEFT JOIN
     Dim_CustomerOrderTypes
     ON
     AA_FactSalesOrderDetails.[Customer order type] = Dim_CustomerOrderTypes.[Customer order type]



WHERE AA_FactSalesOrderDetails.[Order Date] 
      BETWEEN
      dbo.fnc_M3_sql_datetime_to_M3_date(@StartDate)    /* !!!Procedural Approach!!! */
      AND
      dbo.fnc_M3_sql_datetime_to_M3_date(@EndDate)      /* !!!Procedural Approach!!! */
      AND
      AA_FactSalesOrderDetails.Salesperson = @SalesPersonCode

Solution

  • Since the fnc_M3_sql_datetime_to_M3_date takes a value that is constant throughout the execution of the query, move those two calls (the one with startDate and the one with endDate to the top of your query and assign the returned values to declared variables. Then reference those declared variables below instead of calling the function within the where clause. That may help. Functions sometimes inhibit the formulation of a good query plan.

    This talks a little about it Why do SQL Server Scalar-valued functions get slower? and this too http://strictlysql.blogspot.com/2010/06/scalar-functions-on-where-clause.html

    declare @m3StartDate Numeric(8,0)
    Set @m3StartDate = fnc_M3_sql_datetime_to_M3_date(@StartDate)
    declare @m3EndDate Numeric(8,0)
    Set @m3EndDate = fnc_M3_sql_datetime_to_M3_date(@EndDate)
    ...
    WHERE AA_FactSalesOrderDetails.[Order Date] 
          BETWEEN @m3StartDate AND @m3EndDate
          AND
          AA_FactSalesOrderDetails.Salesperson = @SalesPersonCode
    

    The type of the two @m3-- vars should be exactly the same as AA_FactSalesOrderDetails.[Order Date].

    I would also examine the definition of the key on Dim_Customers that is getting the scan instead of a seek, and ensure Dim_Customers is indexed in a way that helps you if it isn't already. http://blog.sqlauthority.com/2009/08/24/sql-server-index-seek-vs-index-scan-diffefence-and-usage-a-simple-note/