2010-11-18 7 views
0

Je veux optimiser ce SP, tout le monde a une idée de comment je peux faire cela? Merci d'avance.optimisation 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

Avez-vous un plan de requête? Pourquoi pensez-vous que cette ligne est un problème de performance? – Oded

+0

ce n'est pas sur la performance comme c'est pour la condition. tous ces paramètres sont pour un champ de données -> orderstatusID. Si tous sont null, je n'obtiens aucun résultat, mais j'aime obtenir des résultats même quand ils sont nuls, les résultats devraient être basés sur les paramètres pour les autres champs de données – Laziale

+3

Jetez un oeil à l'article de Gail Shaw sur [ requêtes fourre-tout] (http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/). –

Répondre

1

Lorsque vous avez trop de conditions OR, les performances risquent de s'en ressentir (sans compter que cela entraînerait un reniflage des paramètres). Je recommande fortement d'utiliser Dynamic SQL ici. Quelque chose comme ça,

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

SI le OrderStatusID est un champ de bits, suivant pourrait travailler

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 est une valeur entière, et lorsque j'utilise votre exemple, je le fais par exemple: \t COALESCE (@OrderStatusComplete, o.OrderStatusID) et le SP ne retourne aucune valeur. Comment puis-je résoudre ce problème? Merci beaucoup – Laziale

+0

@Laziale, j'ai corrigé une erreur dans le traitement de l'OrderstatusID. Pourriez-vous réessayer. –

0

meilleure source pour les conditions de recherche dynamiques:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

il y a beaucoup de implications subtiles sur la façon dont vous faites cela pour savoir si un index peut être utilisé ou non. Si vous êtes sur la bonne version de SQL Server 2008, vous pouvez simplement ajouter OPTION (RECOMPILE) à la requête et la valeur de la variable locale au moment de l'exécution est utilisée pour les optimisations.

Considérez ceci, OPTION (RECOMPILE) prendra ce code (où aucun indice peut être utilisé avec ce gâchis de OR s):

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

et optimiser au moment de l'exécution à (à condition que seul @ Search2 a été adoptée avec une valeur):

WHERE 
    [email protected] 

et un index peut être utilisé (si vous en avez défini sur Colonne2)

si vous n'êtes pas sur la version nécessaire de SQL Server 2008, l'article lié propose de nombreuses méthodes avec des avantages et des inconvénients pour chacun. Par exemple, si vous pouvez déterminer une plage minimale et maximale pour votre colonne de recherche et que la colonne de recherche n'est PAS NULLE, alors vous pouvez faire mieux que le (@Search IS NULL ou Col = @ Search), see this area of the above linked article. Cependant vous devriez lire l'article entier, il y a tellement de variations qui dépendent de votre situation, vous avez vraiment besoin d'apprendre de multiples approches et quand les utiliser.