Égale (=) vs LIKE

282

Lors de l'utilisation de SQL, y a-t-il des avantages à utiliser =dans une WHEREclause au lieu de LIKE?

Sans opérateurs spéciaux, LIKEet =sont les mêmes, non?

Travis
la source
4
Pourrait vouloir spécifier un type de base de données ... mssql, mysql, oracle?
Allen Rice
1
Votre question a au moins des 5votes pour le tag d' opérateur similaire . Puis-je vous demander de suggérer comme sql-like comme synonyme ?
Kermit
@FreshPrinceOfSO, je le ferai quand j'aurai assez de réputation. Merci.
Travis

Réponses:

271

Différents opérateurs

LIKEet =sont différents opérateurs. La plupart des réponses se concentrent ici sur le support des caractères génériques, ce qui n'est pas la seule différence entre ces opérateurs!

=est un opérateur de comparaison qui opère sur des nombres et des chaînes. Lors de la comparaison de chaînes, l'opérateur de comparaison compare des chaînes entières .

LIKEest un opérateur de chaîne qui compare caractère par caractère .

Pour compliquer les choses, les deux opérateurs utilisent un classement qui peut avoir des effets importants sur le résultat de la comparaison.

Exemple de motivation

Identifions d'abord un exemple où ces opérateurs produisent des résultats évidemment différents. Permettez-moi de citer le manuel MySQL:

Selon le standard SQL, LIKE effectue la correspondance par caractère, il peut donc produire des résultats différents de l'opérateur de comparaison =:

mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
|                                    1 |
+--------------------------------------+

Veuillez noter que cette page du manuel MySQL est appelée Fonctions de comparaison de chaînes et =n'est pas discutée, ce qui implique qu'il =ne s'agit pas strictement d'une fonction de comparaison de chaînes.

Comment ça =marche?

Le SQL Standard § 8.2 décrit comment =compare les chaînes:

La comparaison de deux chaînes de caractères est déterminée comme suit:

a) Si la longueur en caractères de X n'est pas égale à la longueur en caractères de Y, alors la chaîne la plus courte est effectivement remplacée, à des fins de comparaison, par une copie d'elle-même qui a été étendue à la longueur de la chaîne la plus longue par concaténation à droite d'un ou plusieurs caractères de pad, où le caractère de pad est choisi en fonction de CS. Si CS a l'attribut NO PAD, alors le caractère de remplissage est un caractère dépendant de l'implémentation différent de n'importe quel caractère dans le jeu de caractères de X et Y qui rassemble moins que n'importe quelle chaîne sous CS. Sinon, le caractère du tampon est a.

b) Le résultat de la comparaison de X et Y est donné par la séquence de classement CS.

c) Selon la séquence d'assemblage, deux chaînes peuvent se comparer comme égales, même si elles sont de longueurs différentes ou contiennent des séquences de caractères différentes. Lorsque les opérations MAX, MIN, DISTINCT, des références à une colonne de regroupement et les opérateurs UNION, EXCEPT et INTERSECT font référence à des chaînes de caractères, la valeur spécifique sélectionnée par ces opérations dans un ensemble de ces valeurs égales dépend de l'implémentation.

(Je souligne.)

Qu'est-ce que ça veut dire? Cela signifie que lors de la comparaison de chaînes, l' =opérateur n'est qu'un mince wrapper autour du classement actuel. Un classement est une bibliothèque qui a différentes règles pour comparer des chaînes. Voici un exemple de classement binaire de MySQL :

static int my_strnncoll_binary(const CHARSET_INFO *cs __attribute__((unused)),
                               const uchar *s, size_t slen,
                               const uchar *t, size_t tlen,
                               my_bool t_is_prefix)
{
  size_t len= MY_MIN(slen,tlen);
  int cmp= memcmp(s,t,len);
  return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}

Ce classement particulier arrive à comparer octet par octet (c'est pourquoi il est appelé "binaire" - il ne donne aucune signification particulière aux chaînes). D'autres classements peuvent fournir des comparaisons plus avancées.

Par exemple, voici un classement UTF-8 qui prend en charge les comparaisons non sensibles à la casse. Le code est trop long pour être collé ici, mais allez sur ce lien et lisez le corps de my_strnncollsp_utf8mb4(). Ce classement peut traiter plusieurs octets à la fois et il peut appliquer diverses transformations (telles que la comparaison insensible à la casse). L' =opératrice est complètement abstraite des aléas de la collation.

Comment ça LIKEmarche?

Le SQL Standard § 8.5 décrit comment LIKEcompare les chaînes:

Le <prédicat>

M LIKE P

est vrai s'il existe un partitionnement de M en sous-chaînes tel que:

i) Une sous-chaîne de M est une séquence de 0 ou plusieurs <représentation de caractère> contiguës de M et chaque <représentation de caractère> de M fait partie d'exactement une sous-chaîne.

ii) Si le i-ième spécificateur de sous-chaîne de P est un spécificateur de caractère arbitraire, la i-ième sous-chaîne de M est n'importe quelle <représentation de caractère>.

iii) Si le i-ième spécificateur de sous-chaîne de P est un spécificateur de chaîne arbitraire, alors la i-ième sous-chaîne de M est une séquence de 0 ou plus <représentation de caractère> s.

iv) Si le i-ème spécificateur de sous-chaîne de P n'est ni un spécificateur de caractère arbitraire ni un spécificateur de chaîne arbitraire, alors la i-ème sous-chaîne de M est égale à ce spécificateur de sous-chaîne selon la séquence de classement du <prédicat similaire>, sans l'ajout de caractères <espace> à M, et a la même longueur que ce spécificateur de sous-chaîne.

v) Le nombre de sous-chaînes de M est égal au nombre de spécificateurs de sous-chaînes de P.

(Je souligne.)

C'est assez verbeux, alors décomposons-le. Les éléments ii et iii font respectivement référence aux caractères génériques _et %. Si Pne contient aucun caractère générique, seul l'élément iv s'applique. C'est le cas d'intérêt posé par le PO.

Dans ce cas, il compare chaque "sous-chaîne" (caractères individuels) à Mchaque sous-chaîne en Putilisant le classement actuel.

Conclusions

L'essentiel est que lors de la comparaison de chaînes, =compare la chaîne entière tout en LIKEcomparant un caractère à la fois. Les deux comparaisons utilisent le classement actuel. Cette différence conduit à des résultats différents dans certains cas, comme en témoigne le premier exemple de ce post.

Lequel devriez-vous utiliser? Personne ne peut vous le dire - vous devez utiliser celui qui convient à votre cas d'utilisation. N'optimisez pas prématurément en changeant d'opérateurs de comparaison.

Mark E. Haase
la source
4
«EQUALS compare deux éléments de données octet par octet»: trop simplifié et trop souvent faux, car le comportement EQUALS (=) peut être modifié avec COLLATE, ce qui entraîne la comparaison des classes de caractères au lieu des caractères. Voir par exemple dev.mysql.com/doc/refman/5.0/en/charset-collate.html (MySQL) ou sqlmag.com/blog/forcing-collation-where-clause-22-jun-2011 (SQL Server).
Peter B
11
Ceci est la bonne réponse. Nous savons ce qui se LIKEpasse, mais cette réponse explique de manière impressionnante que l'utilisation LIKEsans %ou _présent n'est pas du tout la même chose que l'utilisation =. Que votre réponse reçoive mille votes positifs.
rinogo
1
@mehase cela ne peut pas être vrai. Si mon champ varchar contient la valeur 'AbCdEfG', et je le fais WHERE MyCol = 'abcdefg', je récupère toujours cette ligne, même si elles ne sont clairement pas équivalentes octet par octet
Kip
1
PeterB et @Kip soulèvent tous deux de bons points. J'ai amélioré ma réponse pour essayer d'expliquer comment le classement affecte ces opérateurs.
Mark E. Haase
2
Cela ne semble plus vrai: set charset latin1; SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;donne 0, et SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;donne aussi 0.
joanq
170

L'opérateur égal (=) est un "opérateur de comparaison compare deux valeurs d'égalité". En d'autres termes, dans une instruction SQL, elle ne retournera true que si les deux côtés de l'équation sont égaux. Par exemple:

SELECT * FROM Store WHERE Quantity = 200;

L'opérateur LIKE "implémente une comparaison de correspondance de modèle" qui tente de faire correspondre "une valeur de chaîne à une chaîne de modèle contenant des caractères génériques". Par exemple:

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

LIKE est généralement utilisé uniquement avec des chaînes et égal (je crois) est plus rapide. L'opérateur égal traite les caractères génériques comme des caractères littéraux. La différence dans les résultats retournés est la suivante:

SELECT * FROM Employees WHERE Name = 'Chris';

Et

SELECT * FROM Employees WHERE Name LIKE 'Chris';

Renverrait le même résultat, bien que l'utilisation de LIKE prenne généralement plus de temps car c'est une correspondance de modèle. cependant,

SELECT * FROM Employees WHERE Name = 'Chris%';

Et

SELECT * FROM Employees WHERE Name LIKE 'Chris%';

Renvoyer des résultats différents, où l'utilisation de "=" entraîne uniquement des résultats avec "Chris%" renvoyé et l'opérateur LIKE renvoie tout ce qui commence par "Chris".

J'espère que cela pourra aider. Quelques bonnes informations peuvent être trouvées ici .

achinda99
la source
108
J'ai l'impression que l'OP sait quand utiliser LIKE et quand utiliser =, il se demande simplement s'il y a une différence de performances en l'absence de caractère générique. Cette réponse touche brièvement à cela, mais je pense que 95% de cette réponse n'est pas vraiment pertinente.
Outlaw Programmer
1
Très vrai. Je ne sais pas si la question était la même lorsque j'y ai répondu. Si c'était le cas, j'ai raté la partie qui portait sur la performance. Merci pour l'observation.
achinda99
9
Cette réponse est terrible. LIKE et '=' sont des opérateurs complètement distincts, mais se comportent simplement de la même manière dans certains petits sous-ensembles de cas. Par souci de postérité, veuillez lire le reste des réponses ici, ou au moins google pour "mysql like" avant de le sauvegarder en mémoire.
Mark E. Haase
3
D'un autre côté, cette réponse a répondu à la question que j'avais et recherchée sur Google. Parfois, c'est aussi bien si une réponse répond au titre d'une question, que le contenu.
CorayThan
Une bonne chose à retenir est lorsque vous utilisez char et varchar2. Si vous comparez char avec char. Avant de comparer la base de données, convertissez d'abord la longueur de la première «variable» en celle de la seconde. Si vous comparez char et varchar2, la base de données ne fera rien. docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm
xild
18

Ceci est un copier / coller d'une autre réponse de la mienne pour la question SQL 'like' vs '=' performance :

Un exemple personnel utilisant mysql 5.5: j'avais une jointure interne entre 2 tables, une de 3 millions de lignes et une de 10 000 lignes.

Lors de l'utilisation d'un élément similaire sur un index comme ci-dessous (pas de caractères génériques), cela a pris environ 30 secondes:

where login like '12345678'

en utilisant 'expliquer' j'obtiens:

entrez la description de l'image ici

Lorsque vous utilisez un «=» sur la même requête, cela prend environ 0,1 seconde:

where login ='12345678'

En utilisant «expliquer», j'obtiens:

entrez la description de l'image ici

Comme vous pouvez le voir, la likerecherche d'index a été complètement annulée, la requête a donc pris 300 fois plus de temps.

Aris
la source
17

LIKEet =sont différents. LIKEest ce que vous utiliseriez dans une requête de recherche. Il autorise également les caractères génériques comme _(caractère générique simple) et %(caractère générique à plusieurs caractères).

= devrait être utilisé si vous voulez des correspondances exactes et ce sera plus rapide.

Ce site explique LIKE

WalterJ89
la source
11

Une différence - en dehors de la possibilité d'utiliser des caractères génériques avec LIKE - réside dans les espaces de fin: l'opérateur = ignore l'espace de fin, mais LIKE ne le fait pas.

ISW
la source
4
Bien que cela soit vrai pour MySQL et MS SQL, ce n'est pas le cas pour PostgreSQL.
Bruno
10

Dépend du système de base de données.

Généralement sans caractères spéciaux, oui, = et LIKE sont identiques.

Cependant, certains systèmes de base de données peuvent traiter les paramètres de classement différemment avec les différents opérateurs.

Par exemple, dans MySQL, les comparaisons avec = sur les chaînes sont toujours insensibles à la casse par défaut, donc LIKE sans caractères spéciaux est le même. Sur certains autres SGBDR, LIKE est insensible à la casse tandis que = ne l'est pas.

ʞɔıu
la source
Y a-t-il quelque chose comme un aperçu de cette bizarrerie?
Gumbo
9

Pour cet exemple, nous tenons pour acquis que varcharcol ne contient pas ''et n'a pas de cellule vide contre cette colonne

select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''

Le premier produit une sortie de ligne 0 tandis que le second affiche la liste entière. = correspond strictement à la casse tandis que like agit comme un filtre. si le filtre n'a pas de critère, toutes les données sont valides.

like - en vertu de son objectif, fonctionne un peu plus lentement et est destiné à être utilisé avec varchar et des données similaires.

Arnab
la source
6

Si vous recherchez une correspondance exacte, vous pouvez utiliser à la fois, = et LIKE.

L'utilisation de "=" est un tout petit peu plus rapide dans ce cas (recherche d'une correspondance exacte) - vous pouvez le vérifier vous-même en ayant deux fois la même requête dans SQL Server Management Studio, une fois en utilisant "=", une fois en utilisant "LIKE" et puis en utilisant la "Requête" / "Inclure le plan d'exécution réel".

Exécutez les deux requêtes et vous devriez voir vos résultats deux fois, plus les deux plans d'exécution réels. Dans mon cas, ils ont été divisés à 50% contre 50%, mais le plan d'exécution "=" a un "coût de sous-arbre estimé" plus petit (affiché lorsque vous survolez la case "SELECT" la plus à gauche) - mais encore une fois, c'est vraiment pas une énorme différence.

Mais lorsque vous commencez à rechercher des caractères génériques dans votre expression LIKE, les performances de recherche diminuent. La recherche "LIKE Mill%" peut toujours être assez rapide - SQL Server peut utiliser un index sur cette colonne, s'il y en a un. La recherche de "LIKE% expression%" est horriblement lente, car la seule façon dont SQL Server peut satisfaire cette recherche consiste à effectuer une analyse complète de la table. Soyez donc prudent avec vos LIKE!

Marc

marc_s
la source
-1 comme non, ce n'est pas toujours un tout petit peu plus rapide. Si la colonne est indexée à l'aide de% mystring%, le ralentissement est de quelques ordres de grandeur. En effet, toute norme de code digne de ce nom aura des directives rigoureuses sur le moment et le moment de ne pas l'utiliser comme sur une base de données plus grosse qu'une souris micky.
Cruachan
1
Je n'ai jamais dit que ce serait un tout petit peu plus lent dans tous les cas - j'ai dit que ce serait un tout petit peu plus lent si vous recherchez une correspondance EXACTE. Bien sûr, la recherche avec un LIKE et l'utilisation de caractères génériques, en particulier au début et à la fin de votre élément de recherche, est BEAUCOUP plus lente, sans aucun doute.
marc_s
Et oui, je suis d'accord - il faut avoir des directives claires quant au moment d'utiliser LIKE ou non (uniquement lorsque vous avez besoin de rechercher avec des caractères génériques). Mais là encore - en théorie, il n'y a pas de différence entre la théorie et la pratique, mais en pratique .......
marc_s
6

L'utilisation de = évite les caractères génériques et les conflits de caractères spéciaux dans la chaîne lorsque vous générez la requête au moment de l'exécution.

Cela facilite la vie du programmeur en n'ayant pas à échapper tous les caractères génériques spéciaux qui pourraient se glisser dans la clause LIKE et ne pas produire le résultat souhaité. Après tout, = est le scénario d'utilisation à 99%, ce serait pénible de devoir y échapper à chaque fois.

roule les yeux aux années 90

Je soupçonne également que c'est un peu plus lent, mais je doute que ce soit significatif s'il n'y a pas de caractères génériques dans le modèle.

Coincoin
la source
6

Pour répondre à la question initiale concernant les performances, il s'agit de l' utilisation de l'index . Lorsqu'un simple scan de table se produit, "LIKE" et "=" sont identiques . Lorsque des index sont impliqués, cela dépend de la façon dont la clause LIKE est formée. Plus précisément, quel est l'emplacement du ou des caractères génériques?


Considérer ce qui suit:

CREATE TABLE test(
    txt_col  varchar(10) NOT NULL
)
go

insert test (txt_col)
select CONVERT(varchar(10), row_number() over (order by (select 1))) r
  from master..spt_values a, master..spt_values b
go

CREATE INDEX IX_test_data 
    ON test (txt_col);
go 

--Turn on Show Execution Plan
set statistics io on

--A LIKE Clause with a wildcard at the beginning
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '%10000'
--Results in
--Table 'test'. Scan count 3, logical reads 15404, physical reads 2, read-ahead reads 15416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index SCAN is 85% of Query Cost

--A LIKE Clause with a wildcard in the middle
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '1%99'
--Results in
--Table 'test'. Scan count 1, logical reads 3023, physical reads 3, read-ahead reads 3018, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost for test data, but it may result in a Table Scan depending on table size/structure

--A LIKE Clause with no wildcards
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO

--an "=" clause = does Index Seek same as above
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col = '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO


DROP TABLE test

Il peut également y avoir une différence négligeable dans la création du plan de requête lors de l'utilisation de "=" vs "LIKE".

Laramie
la source
4

Outre les caractères génériques, la différence entre =AND LIKEdépendra à la fois du type de serveur SQL et du type de colonne.

Prenez cet exemple:

CREATE TABLE testtable (
  varchar_name VARCHAR(10),
  char_name CHAR(10),
  val INTEGER
);

INSERT INTO testtable(varchar_name, char_name, val)
    VALUES ('A', 'A', 10), ('B', 'B', 20);

SELECT 'VarChar Eq Without Space', val FROM testtable WHERE varchar_name='A'
UNION ALL
SELECT 'VarChar Eq With Space', val FROM testtable WHERE varchar_name='A '
UNION ALL
SELECT 'VarChar Like Without Space', val FROM testtable WHERE varchar_name LIKE 'A'
UNION ALL
SELECT 'VarChar Like Space', val FROM testtable WHERE varchar_name LIKE 'A '
UNION ALL
SELECT 'Char Eq Without Space', val FROM testtable WHERE char_name='A'
UNION ALL
SELECT 'Char Eq With Space', val FROM testtable WHERE char_name='A '
UNION ALL
SELECT 'Char Like Without Space', val FROM testtable WHERE char_name LIKE 'A'
UNION ALL
SELECT 'Char Like With Space', val FROM testtable WHERE char_name LIKE 'A '
  • À l'aide de MS SQL Server 2012 , les espaces de fin seront ignorés dans la comparaison, sauf LIKElorsque le type de colonne est VARCHAR.

  • Avec MySQL 5.5 , les espaces de fin seront ignorés pour =, mais pas pour LIKE, avec CHARet VARCHAR.

  • En utilisant PostgreSQL 9.1 , les espaces sont importants à la fois =et l' LIKEutilisation VARCHAR, mais pas CHAR(voir la documentation ).

    Le comportement avec LIKEdiffère également avec CHAR.

    En utilisant les mêmes données que ci-dessus, en utilisant une explicite CAST sur le nom de la colonne fait également une différence :

    SELECT 'CAST none', val FROM testtable WHERE char_name LIKE 'A'
    UNION ALL
    SELECT 'CAST both', val FROM testtable WHERE
        CAST(char_name AS CHAR) LIKE CAST('A' AS CHAR)
    UNION ALL
    SELECT 'CAST col', val FROM testtable WHERE CAST(char_name AS CHAR) LIKE 'A'
    UNION ALL
    SELECT 'CAST value', val FROM testtable WHERE char_name LIKE CAST('A' AS CHAR)

    Cela ne renvoie que des lignes pour "CAST both" et "CAST col".

Bruno
la source
2

Le mot-clé LIKE est sans aucun doute accompagné d'une "étiquette de prix de performance". Cela dit, si vous avez un champ de saisie qui pourrait potentiellement inclure des caractères génériques à utiliser dans votre requête, je recommanderais d'utiliser LIKE uniquement si l'entrée contient l'un des caractères génériques. Sinon, utilisez la norme égale à comparaison.

Meilleures salutations...

Josh Stodola
la source
1

Cela dépend vraiment de ce que vous voulez que la requête fasse. Si vous voulez dire une correspondance exacte, utilisez =. Si vous voulez dire une correspondance plus floue, utilisez LIKE. Dire ce que vous voulez dire est généralement une bonne politique avec du code.

pas pas
la source
1

Dans Oracle, un «like» sans caractères génériques renvoie le même résultat qu'un «égal», mais peut nécessiter un traitement supplémentaire. Selon Tom Kyte , Oracle traitera un «comme» sans caractères génériques comme un «égal» lors de l'utilisation de littéraux, mais pas lors de l'utilisation de variables de liaison.

Chris B
la source
0

=et LIKEn'est pas le même;

  1. = correspond à la chaîne exacte
  2. LIKE correspond à une chaîne pouvant contenir des caractères génériques (%)
baretta
la source
2
Réponse insuffisante
Il pourrait être utilisé sans caractères génériques. La question demandait la différence pour les mêmes cas.
M-Razavi