2009-01-23 19 views
2

J'ai une requête de recherche dont j'hérite et que j'essaie d'optimiser. Je suis curieux d'entendre si quelqu'un a des meilleures pratiques et des recommandations pour un tel. Le serveur de production est toujours SQL Server 2000 également. La requête est une procédure stockée de recherche client avancée qui accepte 5 paramètres de critères de recherche différents (par exemple, prénom, nom, adresse, téléphone, etc.) pour rechercher une table d'enregistrements multimilliards. Il y a des index sur toutes les colonnes et colonnes jointes dans la clause WHERE. En outre, la requête initiale vide les enregistrements dans une variable de table pour la capacité de pagination.Quelles sont les meilleures pratiques pour optimiser plusieurs requêtes SQL LIKE à colonnes?

INSERT INTO @tempCustTable (CustomerID, FirstName, LastName, City, StateProvince, Zip, PhoneNumber) 
SELECT DISTINCT cu.CustomerID, cu.FirstName, cu.LastName, a.City, 
a.StateProvince, a.Zip, p.PhoneNumber 
FROM Customer cu WITH(NOLOCK) 
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID 
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID 
WHERE (cu.LastName = @LastName OR cu.LastName LIKE @LastName + '%') 
AND (@FirstName IS NULL OR cu.FirstName = @FirstName OR cu.FirstName LIKE @FirstName + '%') 
AND (@StateProvince = '' OR a.StateProvince LIKE @StateProvince) 
AND (@City = '' OR a.City LIKE @City + '%') 
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%') 
ORDER BY cu.LastName, cu.FirstName 

Quelqu'un at-il des recommandations sur la façon dont je pourrais améliorer les performances de la requête?

Répondre

2

n'est pas toute cette ligne

AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%') 

le même que celui

AND (a.Zip LIKE @Zip + '%') 

sûr

AND (a.Zip LIKE @Zip + '%') 

est le même que

a.Zip = @Zip OR a.Zip LIKE @Zip + '%' 
+0

Bonne question. J'ai besoin de regarder SQL OU à nouveau pour voir si elle évalue les deux côtés indépendamment du retour du côté gauche. – JamesEggers

+0

Il y a une différence en fait ce @Zip = '' retournera aussi des valeurs NULL dans a.Zip c'est ce que vous voulez? – SQLMenace

+0

L'adresse @ City/@ State/@ Zip IS NULL ou la logique vide est adressée et modifiée avant la requête dans la question, donc @Zip = '' est valide. – JamesEggers

0
  • Évitez « OU » s - ils en général empêcher l'utilisation des index
  • Ne placez jamais un « % » sur le côté gauche. - même raison.
+0

Oui, cela peut limiter votre recherche mais LIKE '% des performances des assassinats, et si c'est un problème, il est temps de mettre à jour votre serveur, ou au moins les E/S à une fibre sans stockage. – TravisO

+0

Serait-il préférable de faire une grande quantité d'instructions IF pour construire la requête en fonction de la combinaison de critères que je fournis? On dirait une surcharge et beaucoup de copie et de collage de code, mais je suis un jeu pour essayer différentes choses pour améliorer cela. – JamesEggers

0

Je voudrais essayer de ne pas avoir mon code sql ajouter le '%' mais au lieu de s'attendre à ce que le paramètre l'ait déjà, bien sûr, après l'avoir validé dans votre application! Ensuite, ne pas inclure des comparaisons '=', utiliser comme tout le temps:

OU (cu.LastName COMME @LastName)

au lieu de:

OU (cu.LastName = @LastName OU cu .LastName LIKE @LastName + '%')

+0

Pourquoi le nom de famille = @LastName? Si LastName = @LastName alors il évaluera aussi vrai pour LastName LIKE LastName + '%' –

0

Vous pouvez créer la requête avec SQL dynamique. Cela supprimerait la plupart de vos OR et signifierait également que vous auriez seulement besoin d'inclure dans les lignes d'instructions WHERE les paramètres que l'utilisateur a effectivement entrés. Si vous faites cela, veillez à utiliser sp_executesql plutôt qu'exec afin de pouvoir paramétrer le SQL dynamique afin que le plan de requête puisse être mis en cache.

1

Vous pouvez certainement nettoyer une grande partie de la redondance dans votre code comme SQLMenace indiqué comme un début.

Une autre chose est, ORDER BY ne doit pas être utilisé avec un INSERT..SELECT. ORDER BY n'a aucun sens dans ce contexte. Les gens l'utilisent parfois pour forcer une colonne IDENTITY à se comporter d'une certaine manière, mais c'est une mauvaise habitude IMO. Je ne sais pas si cela aidera dans votre situation, mais une chose que je suis tombé récemment était que dans les procédures stockées SQL Server (j'utilise 2005, mais probablement vrai pour 2000 aussi) ne sera pas court -circuit une condition OU dans de nombreux cas.Par exemple, lorsque vous utilisez:

@my_parameter IS NULL OR my_column = @my_parameter 

il évaluera encore la seconde moitié, même si vous passez une valeur NULL pour @my_parameter. Cela s'est produit même lorsque j'ai défini la procédure stockée à recompiler (et le SELECT). L'astuce consistait à forcer un court-circuit à l'aide d'une instruction CASE. En utilisant cette astuce (et la suppression de la redondance) votre déclaration ressemblerait à ceci:

INSERT INTO @tempCustTable 
(
    CustomerID, 
    FirstName, 
    LastName, 
    City, 
    StateProvince, 
    Zip, 
    PhoneNumber 
) 
SELECT DISTINCT 
    cu.CustomerID, 
    cu.FirstName, 
    cu.LastName, 
    a.City, 
    a.StateProvince, 
    a.Zip, 
    p.PhoneNumber 
FROM Customer cu WITH(NOLOCK) 
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID 
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID 
WHERE 
    (cu.LastName LIKE @LastName + '%') AND 
    (1 = 
      CASE 
       WHEN @FirstName IS NULL THEN 1 
       WHEN cu.FirstName LIKE @FirstName + '%' THEN 1 
       ELSE 0 
      END 
    ) AND 
    (1 = 
      CASE 
       WHEN @StateProvince = '' THEN 1 
       WHEN a.StateProvince = @StateProvince THEN 1 
       ELSE 0 
      END 
    ) AND 
    (1 = CASE 
       WHEN @City = '' THEN 1 
       WHEN a.City LIKE @City + '%' THEN 1 
       ELSE 0 
      END 
    ) AND 
    (1 = CASE 
       WHEN @Zip = '' THEN 1 
       WHEN a.Zip LIKE @Zip + '%' THEN 1 
       ELSE 0 
      END 
    ) 

Il fait la requête plus, et peut-être un peu plus complexe, mais il peut être utile pour une meilleure performance. C'est en particulier true si vos critères incluent une sous-requête qui pourrait autrement être court-circuitée.

Enfin ... être compatible avec vos paramètres. Pour @FirstName, vous recherchez une valeur NULL pour déterminer si elle est utilisée ou non, mais pour les autres, vous recherchez des chaînes vides. Codage de base 101 ici que vous devez faire attention.