开发者

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 @MemberOrderStatusCancelledPendi开发者_运维问答ngNeverPaid 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>


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 ORs):

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.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜