Comment optimiser l'utilisation du « OU » article lorsqu'il est utilisé avec les paramètres (SQL Server 2008)
-
23-09-2019 - |
Question
Je me demande s'il y a un moyen sage de réécrivez la requête suivante afin que les index sur les colonnes utilisées par se optimiseur?
Create Procedure select_Proc1
@Key1 int=0,
@Key2 int=0
As
BEGIN
Select key3
From Or_Table
Where (@key1 =0 OR Key1 =@Key1) AND
(@key2 =0 OR Key2 =@Key2)
END
GO
Même si des colonnes dans les clauses WHERE sont couvertes par des index, SQL Server ne peut pas utiliser ces indices. Cela pose la question de savoir si quelque chose est « blocage » l'utilisation des index. La réponse à cette question est oui - les coupables sont les paramètres et la condition « OU ». Les paramètres ne sont pas couverts par des index, ce qui signifie que SQL Server ne peut pas utiliser les indices pour évaluer « @ key1 = 0 » (une condition qui applique également à @ key2 = 0). En effet, cela signifie que SQL Server ne peut pas utiliser les index pour évaluer la clause « @ key1 = 0 OU clé1 = @ key1 » (comme la clause « OU » est l'union des lignes couvertes par les deux conditions). Le même principe s'applique à l'autre clause (re. Key2) ainsi. Cela conduit SQL Server pour conclure qu'aucun index peut être utilisé pour extraire les lignes, laissant SQL Server pour utiliser la meilleure approche suivante - un balayage index cluster
Comme vous le voyez, l'optimiseur SQL ne sera pas utiliser les index sur les colonnes si les prédicats sont « OU » ed dans la clause WHERE. Une solution à ce problème, est de séparer les requêtes avec la clause IF pour toutes les combinaisons possibles de paramètres.
S'il vous plaît lire cet article court pour obtenir une meilleure vue du problème: http://www.sql-server-performance.com/articles/per/optimize_or_clause_p1.aspx
Maintenant, ma question est, que devons-nous faire si les combinaisons possibles sont plus que seulement trois ou quatre? Rédaction d'une requête distincte pour chaque combinaison ne semble pas une solution rationnelle. Y at-il autre solution pour ce problème?
La solution
SQL Server
est pas très bon dans l'optimisation des prédicats OR
.
Utilisez ceci:
SELECT key3
FROM or_table
WHERE @key1 = 0
AND @key2 = 0
UNION ALL
SELECT key3
FROM or_table
WHERE @key1 = 0
AND @key2 <> 0
AND key2 = @key2
UNION ALL
SELECT key3
FROM or_table
WHERE @key2 = 0
AND @key1 <> 0
AND key1 = @key1
UNION ALL
SELECT key3
FROM or_table
WHERE @key1 <> 0
AND @key2 <> 0
AND key1 = @key1
AND key2 = @key2
SQL Server
regardera les valeurs des variables avant d'exécuter les requêtes et optimiser les requêtes redondantes sur.
Cela signifie qu'une seule requête de quatre sera effectivement exécuté.
Autres conseils
MSSQL 2008 a la syntaxe d'optimisation de la simplification de l'état, il est ici
Where (@key1 =0 OR Key1 =@Key1) AND
(@key2 =0 OR Key2 =@Key2) option(recompile)
Ceci permet d'optimiser l'utilisation des constantes
Avez-vous tente une fonction d'une valeur de table?
CREATE FUNCTION select_func1 (
@Key1 int=0,
@Key2 int=0
)
RETURNS TABLE
AS RETURN (
Select key3
From Or_Table
Where (@key1 =0 OR Key1 =@Key1) AND
(@key2 =0 OR Key2 =@Key2)
)
select * from select_func1(1,2)
Oui - attention utilisation de SQL dynamique va résoudre ce problème. Il y a deux façons de le faire:
a. Si vous êtes un « puriste » à propos de procs stockées, puis composer une chaîne de requête personnalisée dans un proc stocké et exécuter la chaîne. La requête spécifique peut alors être dynamiquement écrit par l'exécution d'inclure uniquement les critères pertinents.
b. Si vous êtes flexible sur l'emplacement de ce SQL, vous pouvez (encore une fois ATTENTIVEMENT) composes la chaîne de requête dans votre application et passez sur le serveur.
Le danger, bien sûr, est d'environ injection SQL. Donc, vous devez être très prudent lorsque les données sont transmises du client dans l'instruction SQL dynamique.
Information complète de Erland Sommarskog: http://www.sommarskog.se/dynamic_sql.html et http://www.sommarskog.se/dyn-search.html