web-dev-qa-db-fra.com

Égal à (=) vs LIKE

Lorsque vous utilisez SQL, l'utilisation de = dans une clause WHERE présente-t-elle des avantages au lieu de LIKE?

Sans opérateurs spéciaux, LIKE et = sont identiques, n'est-ce pas?

266
Travis

Différents opérateurs

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

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

LIKE est 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 motivant

Commençons par identifier un exemple où ces opérateurs produisent des résultats manifestement différents. Permettez-moi de citer le manuel MySQL:

Selon le standard SQL, LIKE effectue une correspondance caractère 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 |
+--------------------------------------+

Notez que cette page du manuel MySQL s'appelle Fonctions de comparaison de chaînes , et que = n'est pas décrit, ce qui implique que = n'est pas strictement une chaîne. fonction de comparaison.

Comment fonctionne =?

Le norme SQL § 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, aux fins de comparaison, par une copie de lui-même qui a été étendue à la longueur de la chaîne la plus longue par concaténation à droite d'un ou de plusieurs caractères de pad, le caractère de pad étant choisi en fonction de CS. Si CS possède l'attribut NO PAD, le caractère de pavé est un caractère dépendant de la mise en œuvre, différent de tout caractère du jeu de caractères de X et Y dont l'assemblage est inférieur à toute chaîne sous CS. Sinon, le caractère du pad est un.

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

c) En fonction de la séquence de classement, deux chaînes peuvent se comparer, même si elles ont des longueurs différentes ou contiennent des séquences de caractères différentes. Lorsque les opérations MAX, MIN, DISTINCT, les 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 valeurs égales dépend de l'implémentation.

(Soulignement ajouté.)

Qu'est-ce que ça veut dire? Cela signifie que lors de la comparaison de chaînes, l’opérateur = n’est qu’une mince couche autour du classement actuel. Un classement est une bibliothèque qui a diverses règles pour comparer des chaînes. Voici un exemple de n 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 compare des octets par octets (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 sans distinction de 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 appliquer diverses transformations (telles que la comparaison sans distinction de casse). L'opérateur = est complètement abstrait des aléas de la collation.

Comment fonctionne LIKE?

Le SQL Standard § 8.5 décrit comment LIKE compare 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ésentations <caractère> contiguës de M et chaque représentation <caractère> de M fait partie d'une seule sous-chaîne.

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

iii) Si le i-ème spécificateur de sous-chaîne de P est un spécificateur de chaîne arbitraire, alors la i-ème sous-chaîne de M est une séquence quelconque 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, la i-ème sous-chaîne de M est égale à ce spécificateur de sous-chaîne selon l'assemblage séquence du prédicat <like>, 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îne de P.

(Soulignement ajouté.)

C'est assez verbeux, alors décomposons-le. Les éléments ii et iii font référence aux caractères génériques _ et %, respectivement. Si P ne 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) dans M à chaque sous-chaîne dans P à l'aide du classement actuel.

Conclusions

La ligne du bas est que lors de la comparaison de chaînes, = compare la chaîne entière, tandis que LIKE compare 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 dire que - vous devez utiliser celui qui convient à votre cas d'utilisation. Ne pas optimiser prématurément en changeant d'opérateur de comparaison.

241
Mark E. Haase

L'opérateur equals (=) est un "opérateur de comparaison compare deux valeurs pour l'égalité". En d'autres termes, dans une instruction SQL, il ne retournera pas vrai à moins que les deux côtés de l'équation soient é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 renvoyé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 longtemps car il s'agit d'un motif. cependant,

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

Et

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

Renverrait des résultats différents, où l'utilisation de "=" donne uniquement le résultat "Chris%" et l'opérateur LIKE renvoie tout ce qui commence par "Chris".

J'espère que ça t'as aidé. Quelques bonnes informations peuvent être trouvées ici .

167
achinda99

LIKE et = sont différents. LIKE est ce que vous utiliseriez dans une requête de recherche. Il autorise également les caractères génériques tels que _ (caractère générique de caractère 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

16
WalterJ89

Ceci est un copier/coller d’une autre de mes réponses à 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.

Lorsque vous utilisez un objet similaire sur un index comme ci-dessous (aucun caractère générique), cela prend environ 30 secondes:

where login like '12345678'

en utilisant 'expliquer' je reçois:

enter image description here

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

where login ='12345678'

En utilisant 'expliquer' je reçois:

enter image description here

Comme vous pouvez le constater, la like a complètement annulé la recherche d'index. La requête a donc pris 300 fois plus de temps.

15
Aris

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

11
ISW

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. Par conséquent, LIKE sans caractères spéciaux est identique. Sur d'autres SGBDR, LIKE est insensible à la casse, tandis que = n'est pas.

10
ʞɔıu

Pour cet exemple, nous partons du principe que varcharcol ne contient pas '' et n’avons aucune 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 alors que le second affiche la liste complète. = correspond strictement à la casse alors que like agit comme un filtre. si le filtre n'a pas de critère, chaque donnée est valide.

like - de par sa fonction, fonctionne un peu plus lentement et est destiné à être utilisé avec varchar et des données similaires.

9
Arnab

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 évitant de devoir échapper à tous les caractères génériques spéciaux susceptibles de glisser dans la clause LIKE et en ne produisant pas le résultat escompté. Après tout, c’est le scénario d’utilisation à 99%, il serait pénible de devoir leur échapper à chaque fois.

roule des yeux dans les années 9

Je pense aussi que c'est un peu plus lent, mais je doute que ce soit significatif s'il n'y a pas de caractère générique dans le modèle.

6
Coincoin

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

Dans ce cas, l’utilisation de "=" est un peu plus rapide (recherche d’une correspondance exacte) - vous pouvez le vérifier vous-même en effectuant deux fois la même requête dans SQL Server Management Studio, une fois avec "=", une fois avec "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 entre 50% et 50%, mais le plan d’exécution "=" a un "coût estimé de sous-arbre" plus petit (affiché lorsque vous survolez la case "SELECT" la plus à gauche). 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 encore être assez rapide - SQL Server peut utiliser un index sur cette colonne, le cas échéant. La recherche "LIKE% expression%" est extrêmement lente, car SQL Server ne peut satisfaire à cette recherche qu'en effectuant une analyse complète de la table. Alors soyez prudent avec vos LIKE!

Marc

6
marc_s

Pour répondre à la question initiale concernant les performances, il s’agit de tilisation de l’index. Quand une simple analyse de table se produit, "LIKE" et "=" sont identiques. Lorsque des index sont impliqués, cela dépend de la manière 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 lorsqu’on utilise "=" vs "LIKE".

6
Laramie

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

Prenons 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 '
  • Avec MS SQL Server 2012 , les espaces de fin seront ignorés dans la comparaison, sauf avec LIKE lorsque le type de colonne est VARCHAR.

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

  • Avec PostgreSQL 9.1 , les espaces sont significatifs avec = et LIKE avec VARCHAR, mais pas avec CHAR (voir documentation ).

    Le comportement avec LIKE diffère également de CHAR.

    En utilisant les mêmes données que ci-dessus, en utilisant un CAST explicite 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 les lignes pour "CAST both" et "CAST col".

4
Bruno

Le mot-clé LIKE vient sans aucun doute avec une "étiquette de prix de performance" attachée. Cela dit, si vous avez un champ de saisie pouvant éventuellement inclure des caractères génériques à utiliser dans votre requête, je vous recommanderais d'utiliser LIKE niquement si l'entrée contient l'un des caractères génériques. Sinon, utilisez le standard égal à la comparaison.

Meilleures salutations...

2
Josh Stodola

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

1
notnot

Dans Oracle, un "similaire" sans aucun caractère générique renvoie le même résultat qu'un "égal", mais peut nécessiter un traitement supplémentaire. Selon Tom Kyte , Oracle traitera un ‘like’ sans aucun caractère générique comme un ‘égal’ lorsqu’il utilise des littéraux, mais pas lorsqu’il utilise des variables de liaison.

1
Chris B

= et LIKE n'est pas la même chose;

  1. = correspond à la chaîne exacte
  2. LIKE correspond à une chaîne pouvant contenir des caractères génériques (%)
0
baretta