Qu'est-ce qui rend une instruction SQL sargable?

253

Par définition (du moins d'après ce que j'ai vu), sargable signifie qu'une requête est capable d'avoir le moteur de requête pour optimiser le plan d'exécution utilisé par la requête. J'ai essayé de chercher les réponses, mais il ne semble pas y avoir beaucoup de choses sur le sujet. La question est donc de savoir ce qui rend ou non une requête SQL sargable. Toute documentation serait grandement appréciée.

Pour référence: SARGable

DForck42
la source
58
+1 pour "sargable". C'est ma parole du jour pour aujourd'hui. :-p
Bfree
1
Je pourrais également ajouter à la réponse d'Adam, que les montagnes d'informations sont dans la plupart des cas extrêmement particulières à chaque moteur de base de données.
Hoagie
31
SARG = Rechercher l'ARGument. Le plus drôle est: "SARG" en allemand signifie "Cercueil", donc je dois toujours sourire quand les gens parlent de SARGABLE - pouvoir être mis dans un cercueil? :-)
marc_s
la durabilité dépend de votre environnement. MySQL est documenté ici: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer
Avoir des champs de texte libre au lieu de "tables de recherche" va également à l'encontre de l'esprit de rendre une requête sargable. Les utilisateurs mal orthographient des éléments lors de la saisie de texte libre (par exemple, le nom de la ville), tandis que les tables de recherche forcent les utilisateurs à choisir une entrée correctement orthographiée. Cela vaut bien le léger problème supplémentaire, car cela peut être correctement indexé au lieu d'utiliser LIKE '% ...%' dans le prédicat.
Ingénieur inversé

Réponses:

256

La chose la plus courante qui rend une requête non-sargable est d'inclure un champ à l'intérieur d'une fonction dans la clause where:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

L'optimiseur SQL ne peut pas utiliser d'index sur myDate, même s'il en existe un. Il devra littéralement évaluer cette fonction pour chaque ligne du tableau. Beaucoup mieux à utiliser:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

Quelques autres exemples:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 
BradC
la source
7
Est-ce que l'inclusion d'une fonction à l'intérieur de GROUP BYla requête rendra la requête non-sargable?
Mike Bailey
1
Certains moteurs de base de données (Oracle, PostgreSQL) prennent en charge les index sur les expressions, vous ne savez pas?
Craig
3
Une version encore meilleure WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))serait-elle SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Un type d'optimisation m'a dit une fois que l'utilisation de OR dans la clause where peut annuler les requêtes ..?
High Plains Grifter du
2
@HighPlainsGrifter vous devez utiliser UNION ALL sur cette requête - l'union a un distinct implicite, ce qui rend une requête beaucoup plus chère qu'elle ne doit l'être quand vous devez des ensembles de données mutuellement exclusifs
Devin Lamothe
1
@BradC Dans MSSQL 2016, il n'y a pas de différence de plan d'exécution entre Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'et Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Ils utilisent tous deux l'index sur FullName et effectuent une recherche d'index.
CEGRD
79

Ne faites pas ça:

WHERE Field LIKE '%blah%'

Cela provoque une analyse de table / index, car la valeur LIKE commence par un caractère générique.

Ne faites pas ça:

WHERE FUNCTION(Field) = 'BLAH'

Cela provoque une analyse de table / index.

Le serveur de base de données devra évaluer FUNCTION () par rapport à chaque ligne du tableau, puis le comparer à 'BLAH'.

Si possible, faites-le à l'envers:

WHERE Field = INVERSE_FUNCTION('BLAH')

Cela exécutera INVERSE_FUNCTION () contre le paramètre une fois et permettra toujours l'utilisation de l'index.

plage
la source
5
Votre suggestion de retourner la fonction ne fonctionnerait vraiment que lorsque la fonction retourne les données (ce qui signifie que f (f (n)) = n).
Adam Robinson
5
Vrai. J'ai envisagé d'ajouter INVERSE_FUNCTION mais je ne voulais pas prêter à confusion. Je vais le changer.
plage du
9

Dans cette réponse, je suppose que la base de données a des index de couverture suffisants. Il y a suffisamment de questions sur ce sujet .

La plupart du temps, la sargabilité d'une requête est déterminée par le point de basculement des index associés. Le point de basculement définit la différence entre rechercher et analyser un index tout en joignant une table ou un ensemble de résultats à une autre. Une recherche est bien sûr beaucoup plus rapide que l'analyse d'une table entière, mais lorsque vous devez rechercher un grand nombre de lignes, une analyse peut avoir plus de sens.

Ainsi, entre autres, une instruction SQL est plus discutable lorsque l'optimiseur s'attend à ce que le nombre de lignes résultantes d'une table soit inférieur au point de basculement d'un index possible sur la table suivante.

Vous pouvez trouver un article détaillé et un exemple ici .

Dries Van Hansewijck
la source
4

Pour qu'une opération soit considérée comme sargable, il ne suffit pas qu'elle puisse simplement utiliser un index existant. Dans l'exemple ci-dessus, l'ajout d'un appel de fonction à une colonne indexée dans la clause where profiterait très probablement de l'index défini. Il va "scanner" aka récupérer toutes les valeurs de cette colonne (index) puis éliminer celles qui ne correspondent pas à la valeur de filtre fournie. Il n'est pas encore suffisamment efficace pour les tables avec un nombre élevé de lignes. Ce qui définit vraiment la sargabilité, c'est la capacité de la requête à parcourir l'index b-tree en utilisant la méthode de recherche binaire qui repose sur l'élimination à demi-ensemble pour le tableau des éléments triés. En SQL, il serait affiché sur le plan d'exécution comme une "recherche d'index".

user2011845
la source