简体   繁体   中英

optimizing SQL SP

I want to optimize this SP, anyone have some idea how I can do that? Thanks in advance.

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON
GO 

ALTER PROCEDURE [dbo].[Members] ( 
  @StartTime datetime = null
  , @EndTime datetime = null
  , @CustomerEmail nvarchar(255) = null
  , @CustomerName nvarchar(255) = null
  , @ShippingMethod nvarchar(255) = null
  , @MemberOrderStatusPending int = null
  , @MemberOrderProcessing int = null
  , @MemberOrderComplete int = null
  , @MemberOrderStatusCancelled int = null
  , @MemberOrderStatusCancelledDiscontinued int = null
  , @MemberOrderStatusCancelledCustomerRequest int = null
  , @MemberOrderStatusCancelledPendingNeverPaid int = null 
 )
 AS 
 BEGIN 

  SET NOCOUNT ON

  SELECT  DISTINCT o.OrderID
          , o.OrderTotal
          , o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName
          , o.CreatedOn AS CreatedOn 
  FROM    Order o
  WHERE   ( o.CreatedOn > @StartTime OR @StartTime IS NULL ) 
          AND ( o.CreatedOn < @EndTime OR @EndTime IS NULL )
          AND ( o.ShippingEmail = @CustomerEmail OR @CustomerEmail IS NULL) 
          AND ( o.BillingFirstName + ' ' + o.BillingLastName = @CustomerName OR @CustomerName IS NULL ) 
          AND ( o.ShippingFirstName + ' ' + o.ShippingLastName = @CustomerName OR @CustomerName IS NULL )
          AND ( o.ShippingMethod = @ShippingMethod OR @ShippingMethod IS NULL )
          AND ( o.OrderStatusID = @MemberOrderProcessing 
                OR o.OrderStatusID = @MemberOrderProcessing 
                OR o.OrderStatusID = @MemberOrderComplete 
                OR o.OrderStatusID = @MemberOrderStatusCancelled 
                OR o.OrderStatusID = @MemberOrderStatusCancelledDiscontinued 
                OR o.OrderStatusID = @MemberOrderStatusCancelledCustomerRequest 
                OR o.OrderStatusID = @MemberOrderStatusCancelledPendingNeverPaid 
                OR @MemberOrderProcessing IS NULL 
                OR @MemberOrderProcessing IS NULL 
                OR @MemberOrderComplete IS NULL 
                OR @MemberOrderStatusCancelled IS NULL 
                OR @MemberOrderStatusCancelledDiscontinued IS NULL 
                OR @MemberOrderStatusCancelledCustomerRequest IS NULL 
                OR @MemberOrderStatusCancelledPendingNeverPaid IS NULL ) 
  ORDER BY 
          o.OrderID

END

When you have that many OR conditions performance is bound to suffer (not to mention that this would lead to parameter sniffing). I would highly recommend using Dynamic SQL here. Something like this,

DECLARE @query VARCHAR(MAX)

SET @query = 
'SELECT DISTINCT o.OrderID, o.OrderTotal, o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName, o.CreatedOn AS CreatedOn FROM Order o 
WHERE 1=1 '

IF @StartTime IS NOT NULL 
 SET @query = @query + ' AND o.CreatedOn > @StartTime' 

IF @EndTime IS NOT NULL
 SET @query = @query + ' AND o.CreatedOn < @EndTime'

IF @CustomerEmail IS NOT NULL
 SET @query = @query + ' AND o.ShippingEmail = @CustomerEmail'
......
......

exec sp_executesql @query,
  N'@StartTime DATETIME,
    @EndTime DATETIME,
    ...<other param definitions>',
  @StartTime,
  @EndTime,
  .. <other param values>

IF the OrderStatusID is a bit field, following might work

SELECT  DISTINCT o.OrderID
          , o.OrderTotal
          , o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName
          , o.CreatedOn AS CreatedOn 
  FROM    Order o
  WHERE   ( o.CreatedOn > COALESCE( @StartTime, '01-01-1899' ))
          AND ( o.CreatedOn < COALESCE( @EndTime, '01-01-2099' ))
          AND ( o.BillingFirstName + ' ' + o.BillingLastName = COALESCE( @CustomerName, o.BillingFirstName + ' ' + o.BillingLastName )) 
          AND ( o.ShippingFirstName + ' ' + o.ShippingLastName = COALESCE (@CustomerName, o.ShippingFirstName + ' ' + o.ShippingLastName ))          
          AND ( o.ShippingEmail = COALESCE(@CustomerEmail, o.ShippingEmail ) 
          AND ( o.ShippingMethod = COALESCE ( @ShippingMethod, o.ShippingMethod )
          AND ( o.OrderStatusID & ( 
                  COALESCE ( @MemberOrderProcessing, 1 )
                  | COALESCE ( @MemberOrderComplete, 2 )
                  | COALESCE ( @MemberOrderStatusCancelled , 4 )
                  | COALESCE ( @MemberOrderStatusCancelledDiscontinued , 8 )
                  | COALESCE ( @MemberOrderStatusCancelledCustomerRequest , 16 )
                  | COALESCE ( @MemberOrderStatusCancelledPendingNeverPaid , 32 )
                ) >= 1
              ) 
  ORDER BY 
          o.OrderID

best source for dynamic search conditions:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

there are a lot of subtle implications on how you do this as to if an index can be used or not. If you are on the proper release of SQL Server 2008 you can just add OPTION (RECOMPILE) to the query and the local variable's value at run time is used for the optimizations.

Consider this, OPTION (RECOMPILE) will take this code (where no index can be used with this mess of OR s):

WHERE
    (@search1 IS NULL or Column1=@Search1)
    AND (@search2 IS NULL or Column2=@Search2)
    AND (@search3 IS NULL or Column3=@Search3)

and optimize it at run time to be (provided that only @Search2 was passed in with a value):

WHERE
    Column2=@Search2

and an index can be used (if you have one defined on Column2)

if you are not on the needed release of SQL Server 2008, the linked article offers many methods with pros and cons for each. for example, if you can determine a min and a max possible range for your search column, and the search column is NOT NULL, then you can do better than the (@Search IS NULL OR Col=@Search), see this area of the above linked article . However you should read the entire article, there are so many variations that depend on your situation, you really need to learn multiple approaches and when to use them.

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