2009-07-08 10 views
1

Ceci est en quelque sorte une suite à Slow Exists Check. La suggestion d'Alex fonctionne et évite avec succès la répétition du code, mais je me retrouve quand même avec un deuxième problème. Considérons l'exemple ci-dessous (De AlexKuznetsov). Dans celui-ci, j'ai deux branches pour gérer 1 contrainte. Si j'avais 2 contraintes optionnelles, je me retrouverais avec 4 branches. Fondamentalement, le nombre de branches augmente exponentiellement avec le nombre de contraintes. D'un autre côté, si j'utilise une fonction de table multi-instructions ou si j'utilise des tables temporaires, l'optimiseur de requêtes SQL ne peut pas m'aider, donc les choses deviennent plus lentes. Je suis un peu méfiant de SQL dynamique (et j'ai entendu dire que c'est lent, aussi).Gestion efficace de plusieurs contraintes optionnelles dans la clause Where

Quelqu'un peut-il offrir des suggestions sur la façon d'ajouter plus de contraintes sans ajouter beaucoup d'instructions if?

Note: J'ai déjà essayé de chaîner x is null or inpo = @inpo ensemble, mais c'est très lent. Gardez à l'esprit que même si le test inpo = @inpo peut être géré via une sorte de magie noire d'indexation, le test de nullité finit par être évalué pour chaque ligne de la table.

IF @inpo IS NULL BEGIN 
    SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1) 
    ORDER BY c; 
END ELSE BEGIN 
    SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1) 
    WHERE inpo = @inpo 
    ORDER BY c; 
END 

Variation Deux: 2 contraintes:

IF @inpo IS NULL BEGIN  
    IF @inpo2 IS NULL BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     ORDER BY c; 
    END ELSE BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo2 = @inpo2 
     ORDER BY c; 
    END 
END ELSE BEGIN 
    IF @inpo2 IS NULL BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo = @inpo 
     ORDER BY c; 
    END ELSE BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo = @inpo AND 
       inpo2 = @inpo2 
     ORDER BY c; 
    END 
END 

Répondre

0
Select blah from foo  
Where (@inpo1 is null or @inpo1 = inpo1) 
and (@inpo2 is null or @inpo2 = inpo2) 

Apparemment, cela est trop lent. Intéressant.

Avez-vous considéré la génération de code? Des requêtes longues avec beaucoup de duplication sont seulement un problème si elles doivent être maintenues directement.

+0

Comme je l'ai mentionné dans Slow Exists vérifier, cette solution est lente. – Brian

0

Voici un exemple approximatif. Modifier les instructions LIKE dans la clause WHERE selon si vous voulez "commence par" ou "contient" ou une correspondance exacte dans votre requête.

CREATE PROCEDURE dbo.test 
@name  AS VARCHAR(50) = NULL, 
@address1  AS VARCHAR(50) = NULL, 
@address2  AS VARCHAR(50) = NULL, 
@city  AS VARCHAR(50) = NULL, 
@state  AS VARCHAR(50) = NULL, 
@zip_code  AS VARCHAR(50) = NULL 
AS 

BEGIN 

SELECT [name], 
      address1, 
      address2, 
      city, 
      state, 
      zip_code 
FROM my_table 
WHERE ([name] LIKE @name + '%' OR @name IS NULL) 
      AND (address1 LIKE @address1 + '%' OR @address1 IS NULL) 
      AND (address2 LIKE @address2 + '%' OR @address2 IS NULL) 
      AND (city LIKE @city + '%' OR @city IS NULL) 
      AND (state LIKE @state + '%' OR @state IS NULL) 
      AND (zip_code LIKE @zip_code + '%' OR @zip_code IS NULL) 
ORDER BY [name] 
END 
GO 
+0

J'ai essayé cela précédemment (mentionné dans la question initiale). C'est lent. – Brian

0

Je me rends compte de votre question peut être purement académique, mais si vous avez des cas réels d'utilisation du monde avez-vous pensé que fournir des requêtes optimisées pour les scénarios les plus courants?

+0

J'ai pensé à cela comme une solution, mais considérez cela comme quelque chose à utiliser si je n'ai pas d'autre choix qu'un idéal. – Brian

1

Dans ce cas, j'utilise sp_executesql comme décrit dans l'article de Erland: Using sp_executesql Chaque fois que SQL dynamique est utilisé, les autorisations manquantes peut être un problème, donc j'ai un compte réel réseau pour les tests unitaires, j'ajouter ce compte au rôle réel , et j'emprunte l'identité avec ce compte réel chaque fois que je teste SQL dynamique, comme décrit ici: Database Unit Testing: Impersonation

+0

Oui, c'est ce que j'ai fini par utiliser. – Brian

Questions connexes