优化SQL SP

时间:2010-11-18 17:19:10

标签: sql sql-server stored-procedures

我想优化这个SP,任何人都知道我该怎么做?提前谢谢。

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

3 个答案:

答案 0 :(得分:1)

当你有那么多OR条件时,性能肯定会受到影响(更不用说这会导致参数嗅探)。我强烈建议在这里使用Dynamic SQL。像这样的东西,

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>

答案 1 :(得分:0)

如果OrderStatusID是位字段,则可能会有以下操作

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

答案 2 :(得分:0)

动态搜索条件的最佳来源:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

如果可以使用索引,对于如何执行此操作会有很多微妙的含义。如果您使用的是SQL Server 2008的正确版本,则只需将OPTION (RECOMPILE)添加到查询中,并将运行时的局部变量值用于优化。

考虑到这一点,OPTION (RECOMPILE)将采用此代码(其中没有索引可用于此OR的混乱):

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

并在运行时优化它(假设只有@ Search2传入了一个值):

WHERE
    Column2=@Search2

并且可以使用索引(如果在Column2上定义了一个索引)

如果您没有使用SQL Server 2008所需的版本,则链接文章提供了许多方法,每种方法都有利弊。例如,如果您可以确定搜索列的最小和最大可能范围,并且搜索列为NOT NULL,那么您可以做得比(@Search IS NULL或Col = @ Search)更好,{{3} }。但是你应该阅读整篇文章,有很多变化取决于你的情况,你真的需要学习多种方法以及何时使用它们。