119 votes

Performances du langage SQL "like" et "=".

Cette question contourne ce que je me demande, mais les réponses ne l'abordent pas exactement.

Il semblerait que en général '=' est plus rapide que 'like' lors de l'utilisation de caractères génériques. Cela semble être la sagesse conventionnelle. Toutefois, supposons que je dispose d'une colonne contenant un nombre limité de différents identifiants fixes, codés en dur, de type varchar, et que je souhaite sélectionner toutes les lignes correspondant à l'un d'entre eux :

select * from table where value like 'abc%'

y

select * from table where value = 'abcdefghijklmn'

La fonction "Like" ne devrait avoir besoin de tester que les trois premiers caractères pour trouver une correspondance, alors que la fonction "=" doit comparer la chaîne entière. Dans ce cas, il me semble que "like" aurait un avantage, toutes choses égales par ailleurs.

Il s'agit d'une question générale et académique, et le type de base de données ne devrait donc pas avoir d'importance, mais le problème est apparu avec SQL Server 2005.

30 votes

Une chose importante que vous avez oubliée est de savoir si oui ou non value est indexé. Si c'est le cas, alors = est une simple recherche sans balayage de table nécessaire et battra à plates coutures n'importe quelle LIKE que vous lui envoyez.

8 votes

@Daniel Je pense que c'est incorrect. A LIKE avec un caractère générique à la fin est SARGable et va donc effectuer une recherche de plage sur un index, sans balayage de table en vue. Cette recherche de plage peut rivaliser assez facilement avec une recherche de type = et dans de nombreux cas (par exemple si toutes les lignes satisfaisantes sont sur une page, une condition non improbable), les performances pourraient être exactement les mêmes, avec le même nombre de lectures.

0 votes

Mon "toutes choses égales par ailleurs" visait à couvrir la question de "l'indexation ou non", mais il semble qu'il y ait au moins une certaine controverse sur la différence que cela ferait, d'après mes commentaires sur les autres réponses.

83voto

BonyT Points 6465

Ver https://web.archive.org/web/20150209022016/http://myitforum.com/cs2/blogs/jnelson/archive/2007/11/16/108354.aspx

Citation de là :

les règles d'utilisation des index avec LIKE sont en gros les suivantes :

  • Si votre critère de filtrage utilise des égaux = et que le champ est indexé, alors le plus probablement qu'il utilisera un INDEX/CLUSTERED RECHERCHE D'INDEX

  • Si votre critère de filtrage utilise LIKE, sans caractères génériques (comme si vous aviez un paramètre paramètre dans un rapport Web qui POURRAIT avoir un % mais que vous utilisez plutôt la complète), il est à peu près aussi probable que le critère #1 d'utiliser l'index. L'augmentation du coût est presque nul.

  • Si votre critère de filtrage utilise LIKE, mais avec un caractère générique au début (comme (comme dans Name0 LIKE '%UTER'), il est beaucoup moins moins susceptible d'utiliser l'index, mais il mais il peut au moins effectuer un SCAN D'INDEX sur sur une plage complète ou partielle de l'index.

  • CEPENDANT, si votre critère de filtrage utilise LIKE, mais commence par une STRING FIRST et comporte des caractères génériques quelque part APRÈS cela (comme dans Name0 LIKE 'COMP%ER'), alors SQL peut simplement utiliser un INDEX SEEK pour trouver rapidement rapidement les lignes qui ont la même première premiers caractères de départ, puis rechercher puis rechercher une correspondance exacte dans ces enregistrements.

(Gardez aussi à l'esprit que le moteur SQL n'utilise pas forcément un index de la manière que vous attendez, en fonction de ce qui ce qui se passe dans votre requête et les tables que vous joignez. Le site moteur SQL se réserve le droit de réécrire un peu votre requête pour obtenir les données d'une manière qu'il pense être la plus efficace, ce qui peut inclure un INDEX SCAN au lieu d'un INDEX SEEK)

59voto

JNK Points 32743

C'est une différence mesurable.

Exécutez ce qui suit :

Create Table #TempTester (id int, col1 varchar(20), value varchar(20))
go

INSERT INTO #TempTester (id, col1, value)
VALUES
(1, 'this is #1', 'abcdefghij')
GO

INSERT INTO #TempTester (id, col1, value)
VALUES
(2, 'this is #2', 'foob'),
(3, 'this is #3', 'abdefghic'),
(4, 'this is #4', 'other'),
(5, 'this is #5', 'zyx'),
(6, 'this is #6', 'zyx'),
(7, 'this is #7', 'zyx'),
(8, 'this is #8', 'klm'),
(9, 'this is #9', 'klm'),
(10, 'this is #10', 'zyx')
GO 10000

CREATE CLUSTERED INDEX ixId ON #TempTester(id)CREATE CLUSTERED INDEX ixId ON #TempTester(id)

CREATE NONCLUSTERED INDEX ixTesting ON #TempTester(value)

Ensuite :

SET SHOWPLAN_XML ON

Ensuite :

SELECT * FROM #TempTester WHERE value LIKE 'abc%'

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

Le plan d'exécution qui en résulte vous montre que le coût de la première opération, le LIKE comparaison, est d'environ 10 fois plus cher que le = comparaison.

Si vous pouvez utiliser un = comparaison, veuillez le faire.

4 votes

+1 pour l'avoir testé. Le simple fait de regarder le plan d'exposition ne donne pas forcément une image complète de la situation. Je vais faire mes propres tests et je vous ferai savoir si je trouve quelque chose d'inattendu.

1 votes

Tom - c'est vrai, mais cela m'a donné suffisamment d'indications que les deux n'étaient PAS traités de la même manière en coulisses.

1 votes

Les coûts indiqués dans le plan d'exécution sont erronés. Ils ne reflètent pas l'exécution réelle. Dans le premier plan, ils sont basés sur un nombre de rowc estimés à 1 000. 19.95 Ainsi, le serveur SQL coûte 19 consultations de clés supplémentaires qui ne se matérialisent jamais dans la réalité. réel plan d'exécution, les coûts indiqués sont basés sur Estimation de coût du sous-arbre)

14voto

Blindy Points 26706

Vous devez également garder à l'esprit que lorsque vous utilisez like En effet, certaines versions de SQL ignorent les index, ce qui nuit aux performances. C'est particulièrement vrai si vous n'utilisez pas le modèle "commence par" comme dans votre exemple.

Vous devriez vraiment regarder le plan d'exécution de la requête et voir ce qu'elle fait, en devinant le moins possible.

Ceci étant dit, le modèle "commence par" peut et est optimisé dans sql server. C'est se utiliser l'index de la table. EF 4.0 est passé à like para StartsWith pour cette même raison.

2 votes

Aucune base de données relationnelle digne de ce nom n'ignorera un index lorsque le modèle similaire fait partie de la requête et que le caractère générique se trouve à la fin. La situation peut être différente si vous liez la valeur et que la base de données prend en charge la liaison séparément de la préparation de la requête.

0 votes

C'est ce que mon instinct me dit aussi, mais je n'ai d'expérience pratique qu'avec sql server à cet égard, donc je me suis concentré sur lui spécifiquement.

8voto

Remus Rusanu Points 159382

Vous posez la mauvaise question. Dans les bases de données, ce n'est pas la performance de l'opérateur qui compte, c'est toujours la performance de l'utilisateur. SARGabilité de l'expression, et le couvrabilité de la requête globale. Les performances de l'opérateur lui-même ne sont pas pertinentes.

Alors, comment LIKE y = sont-elles comparables en termes de SARGabilité ? LIKE lorsqu'il est utilisé avec une expression qui ne commence pas par une constante (par exemple, lorsqu'il est utilisé avec l'expression LIKE '%something' ) est par définition non-SARGabale. Mais est-ce que cela rend = o LIKE 'something%' SARGable ? Non. Comme pour toute question relative aux performances de SQL, la réponse ne réside pas dans la requête du texte, mais dans le schéma déployé. Ces expressions mai être SARGable si un index existe pour les satisfaire.

Donc, à vrai dire, il y a de petites différences entre = y LIKE . Mais demander si un opérateur ou un autre est "plus rapide" en SQL, c'est comme demander "Qu'est-ce qui va plus vite, une voiture rouge ou une voiture bleue ? Vous devriez poser des questions sur la taille du moteur et le poids du véhicule, pas sur la couleur... Pour aborder les questions relatives à l'optimisation des tables relationnelles, l'endroit où il faut chercher est votre indices et votre expressions dans la clause WHERE (et d'autres clauses, mais cela commence généralement par la clause WHERE).

7voto

Will A Points 16763

Si value n'est pas indexé, les deux résultent en un balayage de table. La différence de performance dans ce scénario sera négligeable.

Si value est indexée, comme le souligne Daniel dans son commentaire, l'option = entraînera une recherche d'index dont la performance est de O(log N). Le LIKE donnera (très probablement - en fonction de sa sélectivité) lieu à un balayage partiel de l'index. >= 'abc' y < 'abd' ce qui demandera plus d'efforts que le = .

Notez que je parle ici de SQL Server - tous les SGBD ne seront pas agréables avec LIKE.

0 votes

Je ne pense pas que tu saches comment fonctionne la recherche binaire. Les deux = et l'affaire like '...%' se comportent de la même manière si sql reconnaît le motif (et c'est le cas), car dans les deux cas, les sous-arbres sont choisis sur la base de relations de comparaison.

0 votes

Oh, je le fais. LIKE se comportera probablement plus mal, bien que ce soit toujours O(log N) si la sélectivité est suffisamment élevée - O(log N) pour trouver où commencer le balayage partiel, puis un certain nombre de lectures en avant à travers l'index jusqu'au point final. 'abd' est atteint.

0 votes

Oui, mais l'exemple de l'OP suppose qu'il n'y a qu'une seule valeur dans cette plage, donc avec cela en tête, les comparaisons seront identiques.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X