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 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.
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
精彩评论