2010-11-18 13 views
0

Ich möchte diesen SP zu optimieren, jemand eine Idee, wie ich das tun kann? Danke im Voraus.Optimierung SQL 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 
+1

Haben Sie einen Abfrageplan? Warum denken Sie, dass diese Linie ein Leistungsproblem ist? – Oded

+0

es geht nicht um die Leistung wie es für die Bedingung ist. all diese Parameter sind für ein Datenfeld -> orderstatusID. Wenn alle null sind, bekomme ich keine Ergebnisse, aber ich möchte Ergebnisse erhalten, selbst wenn sie null sind, die Ergebnisse sollten auf den Parametern für die anderen Datenfelder basieren. – Laziale

+3

Werfen Sie einen Blick auf Gail Shaws Blog-Post auf [ Catch-All-Abfragen] (http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/). –

Antwort

1

Wenn Sie so viele OP-Bedingungen haben, wird die Leistung darunter leiden (ganz zu schweigen davon, dass dies zu Parameter-Sniffing führen würde). Ich würde sehr empfehlen, hier Dynamic SQL zu verwenden. So etwas wie dies,

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> 
0

IF das OrderStatusID ein Bit-Feld ist, folgende könnte

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

orderStatusID ist ein Ganzzahlwert, und wenn ich Ihr Beispiel verwende, mache ich zum Beispiel: \t COALESCE (@OrderStatusComplete, o.OrderStatusID) und dann gibt der SP keine Werte zurück. Wie kann ich das beheben? Vielen Dank – Laziale

+0

@Laziale, ich habe einen Fehler bei der Verarbeitung der OrderstatusID behoben. Könnten Sie es erneut versuchen? –

0

beste Quelle für dynamische Suchbedingungen arbeiten:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

gibt es eine Menge von subtile Auswirkungen auf, wie Sie dies tun, wenn ein Index verwendet werden kann oder nicht. Wenn Sie die richtige Version von SQL Server 2008 verwenden, können Sie einfach OPTION (RECOMPILE) zu der Abfrage hinzufügen, und der Wert der lokalen Variablen zur Laufzeit wird für die Optimierungen verwendet.

das Betrachten wir nehmen OPTION (RECOMPILE) diesen Code (wo kein Index mit diesem Durcheinander von OR s verwendet werden können):

WHERE 
    (@search1 IS NULL or [email protected]) 
    AND (@search2 IS NULL or [email protected]) 
    AND (@search3 IS NULL or [email protected]) 

und optimieren es zur Laufzeit werden (vorausgesetzt, dass nur @ Search2 übergeben wurde mit einem Wert):

WHERE 
    [email protected] 

und einem Index kann (wenn Sie ein auf Column2)

wenn Sie nicht auf definiert haben verwendet werden Der verknüpfte Artikel bietet die erforderliche Version von SQL Server 2008 und bietet viele Methoden mit Vor- und Nachteilen für jeden. Wenn Sie zum Beispiel einen minimalen und einen maximalen möglichen Bereich für Ihre Suchspalte bestimmen können und die Suchspalte NOT NULL ist, können Sie besser als die (@Search IS NULL OR Col = @ Suche), see this area of the above linked article. Allerdings sollten Sie den gesamten Artikel lesen, es gibt so viele Variationen, die von Ihrer Situation abhängen, Sie müssen wirklich mehrere Ansätze lernen und wann Sie sie verwenden.