Igual (=) x LIKE

280

Ao usar o SQL, existem benefícios em usar =uma WHEREcláusula em vez de LIKE?

Sem operadores especiais, LIKEe =são os mesmos, certo?

Travis
fonte
4
Pode querer especificar um tipo de db ... mssql, mysql, oracle?
Allen arroz
1
Sua pergunta tem pelo menos 5votos para a tag de operador like . Posso pedir que você sugira sql-like como sinônimo ?
Caco
@FreshPrinceOfSO, farei isso quando tiver reputação suficiente. Obrigado.
Travis

Respostas:

270

Operadores diferentes

LIKEe =são operadores diferentes. A maioria das respostas aqui se concentra no suporte a caracteres curinga, que não é a única diferença entre esses operadores!

=é um operador de comparação que opera em números e seqüências de caracteres. Ao comparar cadeias, o operador de comparação compara cadeias inteiras .

LIKEé um operador de cadeia que compara caractere por caractere .

Para complicar, os dois operadores usam um agrupamento que pode ter efeitos importantes no resultado da comparação.

Exemplo Motivador

Vamos primeiro identificar um exemplo em que esses operadores produzem resultados obviamente diferentes. Permita-me citar o manual do MySQL:

De acordo com o padrão SQL, o LIKE executa a correspondência por caractere, portanto, pode produzir resultados diferentes do operador = comparação:

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 |
+--------------------------------------+

Por favor note que esta página do manual do MySQL se chama String Comparison Functions , e =não é discutida, o que implica que =não é estritamente uma função de comparação de strings.

Como =funciona?

O padrão 8.2 do SQL descreve como =compara cadeias:

A comparação de duas cadeias de caracteres é determinada da seguinte maneira:

a) Se o comprimento em caracteres de X não for igual ao comprimento em caracteres de Y, a sequência mais curta será efetivamente substituída, para fins de comparação, por uma cópia de si mesma que foi estendida para o comprimento da sequência mais longa por concatenação à direita de um ou mais caracteres do bloco, em que o caractere do bloco é escolhido com base no CS. Se CS tiver o atributo NO PAD, o caractere de preenchimento será um caractere dependente de implementação diferente de qualquer caractere no conjunto de caracteres de X e Y que agrupe menos do que qualquer sequência de caracteres em CS. Caso contrário, o caractere de bloco é a.

b) O resultado da comparação de X e Y é dado pela sequência de ordenação CS.

c) Dependendo da sequência de ordenação, duas cadeias podem ser comparadas como iguais, mesmo que tenham comprimentos diferentes ou contenham sequências diferentes de caracteres. Quando as operações MAX, MIN, DISTINCT, referenciam uma coluna de agrupamento e os operadores UNION, EXCEPT e INTERSECT se referem a cadeias de caracteres, o valor específico selecionado por essas operações em um conjunto de valores iguais depende da implementação.

(Enfase adicionada.)

O que isto significa? Isso significa que, ao comparar seqüências de caracteres, o =operador é apenas um invólucro fino em torno do agrupamento atual. Um agrupamento é uma biblioteca que possui várias regras para comparar seqüências de caracteres. Aqui está um exemplo de agrupamento binário do 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);
}

Esse agrupamento em particular compara byte a byte (e é por isso que é chamado de "binário" - não dá nenhum significado especial às strings). Outros agrupamentos podem fornecer comparações mais avançadas.

Por exemplo, aqui está um agrupamento UTF-8 que suporta comparações que não diferenciam maiúsculas de minúsculas. O código é muito longo para colar aqui, mas vá para esse link e leia o corpo de my_strnncollsp_utf8mb4(). Esse agrupamento pode processar vários bytes por vez e aplicar várias transformações (como comparação sem distinção entre maiúsculas e minúsculas). O =operador é completamente abstraído dos caprichos do agrupamento.

Como LIKEfunciona?

O SQL Standard § 8.5 descreve como se LIKEcomparam as strings:

O <predicado>

M LIKE P

é verdadeiro se existir um particionamento de M em substrings, de modo que:

i) Uma substring de M é uma sequência de 0 ou mais <representação de caractere> s contígua de M e cada <representação de caractere> de M faz parte de exatamente uma substring.

ii) Se o i-ésimo especificador de substring de P for um especificador arbitrário de caracteres, o i-ésimo substring de M será qualquer <representação de caractere> única.

iii) Se o i-ésimo especificador de substring de P for um especificador de string arbitrário, o i-ésimo substring de M será qualquer sequência de 0 ou mais <representação de caractere> s.

iv) Se o i-ésimo especificador de substring de P não for um especificador arbitrário de caracteres nem um especificador de string arbitrário, o i-ésimo substring de M será igual a esse especificador de substring, de acordo com a sequência de intercalação do <like predicate>, sem o acréscimo de caracteres <space> a M e tem o mesmo comprimento que o especificador de substring.

v) O número de substrings de M é igual ao número de especificadores de substring de P.

(Enfase adicionada.)

Isso é bastante prolixo, então vamos detalhar. Os itens ii e iii se referem aos caracteres curinga _e %, respectivamente. Se Pnão contiver curingas, apenas o item iv será aplicado. Este é o caso de interesse apresentado pelo OP.

Nesse caso, ele compara cada "substring" (caracteres individuais) Mcom cada substring Pusando o agrupamento atual.

Conclusões

A linha inferior é que, ao comparar cadeias, =compara a cadeia inteira enquanto LIKEcompara um caractere de cada vez. Ambas as comparações usam o agrupamento atual. Essa diferença leva a resultados diferentes em alguns casos, como evidenciado no primeiro exemplo neste post.

Qual deles você deve usar? Ninguém pode lhe dizer isso - você precisa usar o correto para o seu caso de uso. Não otimize prematuramente alternando operadores de comparação.

Mark E. Haase
fonte
4
"EQUALS compara duas partes de dados byte a byte": simplificado demais, e muitas vezes não verdadeiro, porque o comportamento EQUALS (=) pode ser modificado com COLLATE, fazendo com que as classes de caracteres sejam comparadas em vez de caracteres. Por exemplo, consulte 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
Esta é a resposta correta. Sabemos o que LIKEfaz, mas essa resposta explica incrivelmente que usar LIKEsem %ou _presente não é o mesmo que usar =. Que sua resposta receba mil votos positivos.
rinogo
1
@mehase isso não pode ser verdade. Se meu campo varchar contém o valor 'AbCdEfG', e eu faço WHERE MyCol = 'abcdefg', eu ainda obter essa fileira traseira, embora sejam claramente não byte a byte equivalente
Kip
1
PeterB e @Kip levantam bons pontos. Melhorei minha resposta para tentar explicar como o agrupamento afeta esses operadores.
Mark E. Haase
2
Isso não parece mais verdade: set charset latin1; SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;dá 0 e SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;também 0.
Joanq 4/16
170

O operador equals (=) é um "operador de comparação compara dois valores para igualdade". Em outras palavras, em uma instrução SQL, ela não retornará true, a menos que ambos os lados da equação sejam iguais. Por exemplo:

SELECT * FROM Store WHERE Quantity = 200;

O operador LIKE "implementa uma comparação de correspondência de padrões" que tenta corresponder "a um valor de sequência em relação a uma sequência de caracteres contendo caracteres curinga". Por exemplo:

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

LIKE geralmente é usado apenas com strings e iguais (acredito) é mais rápido. O operador equals trata caracteres curinga como caracteres literais. A diferença nos resultados retornados é a seguinte:

SELECT * FROM Employees WHERE Name = 'Chris';

E

SELECT * FROM Employees WHERE Name LIKE 'Chris';

Retornaria o mesmo resultado, embora o uso de LIKE geralmente levasse mais tempo, pois é uma correspondência de padrão. Contudo,

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

E

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

Retornaria resultados diferentes, onde o uso de "=" resulta apenas em resultados com "Chris%" sendo retornados e o operador LIKE retornará qualquer coisa que comece com "Chris".

Espero que ajude. Algumas boas informações podem ser encontradas aqui .

achinda99
fonte
108
Estou com a impressão de que o OP sabe quando usar LIKE e quando usar =, ele está se perguntando se há uma diferença de desempenho quando não há curinga presente. Esta resposta aborda brevemente isso, mas sinto que 95% dessa resposta não é realmente relevante.
Outlaw Programmer
1
Muito verdadeiro. Não tenho certeza se a pergunta era a mesma quando a respondi. Se foi, eu perdi a parte que perguntou sobre o desempenho. Obrigado pela observação.
13259 achinda99
9
Essa resposta é terrível. LIKE e '=' são operadores completamente distintos, mas por acaso se comportam de maneira semelhante em alguns pequenos subconjuntos de casos. Por uma questão de posteridade, leia o restante das respostas aqui, ou pelo menos pesquise "mysql like" no google antes de confirmar isso na memória.
Mark E. Haase
3
Por outro lado, essa resposta respondeu à pergunta que eu tinha e pesquisei no Google. Às vezes, é tão bom se uma resposta responder ao título de uma pergunta quanto ao conteúdo.
precisa saber é o seguinte
É bom lembrar que você está usando char e varchar2. Se você comparar char com char. Antes de comparar o banco de dados, primeiro converta o comprimento da primeira 'variável' para a mesma do segundo. Se você comparar char e varchar2, o banco de dados não fará nada. docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm
xild
18

Esta é uma cópia / pasta de outra resposta minha para a pergunta SQL 'like' vs '=' performance :

Um exemplo pessoal usando o mysql 5.5: eu tive uma junção interna entre 2 tabelas, uma de 3 milhões de linhas e uma de 10 mil linhas.

Ao usar um like em um índice como abaixo (sem curingas), demorou cerca de 30 segundos:

where login like '12345678'

usando 'explicar' eu recebo:

insira a descrição da imagem aqui

Ao usar um '=' na mesma consulta, demorou cerca de 0,1 segundos:

where login ='12345678'

Usando 'explicar' eu recebo:

insira a descrição da imagem aqui

Como você pode ver, a likebusca do índice foi completamente cancelada, portanto, a consulta levou 300 vezes mais tempo.

Aris
fonte
17

LIKEe =são diferentes. LIKEé o que você usaria em uma consulta de pesquisa. Também permite curingas como _(curinga de caractere simples) e %(curinga de vários caracteres).

= deve ser usado se você quiser correspondências exatas e será mais rápido.

Este site explica LIKE

WalterJ89
fonte
11

Uma diferença - além da possibilidade de usar curingas com LIKE - está nos espaços à direita: O operador = ignora o espaço à direita, mas LIKE não.

ISW
fonte
4
Embora isso seja verdade para MySQL e MS SQL, isso não é para PostgreSQL.
de Bruno
10

Depende do sistema de banco de dados.

Geralmente sem caracteres especiais, sim, = e LIKE são iguais.

Alguns sistemas de banco de dados, no entanto, podem tratar as configurações de agrupamento de maneira diferente com os diferentes operadores.

Por exemplo, no MySQL as comparações com = on strings sempre diferenciam maiúsculas de minúsculas por padrão, então LIKE sem caracteres especiais é o mesmo. Em alguns outros RDBMS, LIKE não diferencia maiúsculas de minúsculas, enquanto = não é.

ʞɔıu
fonte
Existe algo como uma visão geral para essa estranheza?
Gumbo
9

Para este exemplo, assumimos que o varcharcol não contém ''e não possui célula vazia nessa coluna

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

O primeiro resulta na saída de 0 linhas, enquanto o segundo mostra a lista inteira. = é estritamente compatível com maiúsculas e minúsculas, enquanto o tipo age como um filtro. se o filtro não tiver critérios, todos os dados serão válidos.

like - em virtude de sua finalidade, funciona um pouco mais devagar e se destina ao uso com varchar e dados semelhantes.

Arnab
fonte
6

Se você procurar uma correspondência exata, poderá usar ambos, = e LIKE.

Usar "=" é um pouquinho mais rápido nesse caso (procurando uma correspondência exata) - você mesmo pode verificar isso fazendo a mesma consulta duas vezes no SQL Server Management Studio, uma vez usando "=", uma vez usando "LIKE" e depois, usando a opção "Consulta" / "Incluir plano de execução real".

Execute as duas consultas e você verá os resultados duas vezes, além dos dois planos de execução reais. No meu caso, eles foram divididos em 50% vs. 50%, mas o plano de execução "=" tem um "custo estimado de subárvore" menor (exibido quando você passa o mouse sobre a caixa "SELECT" mais à esquerda) - mas, novamente, é realmente não é uma diferença enorme.

Mas quando você começa a procurar com curingas na sua expressão LIKE, o desempenho da pesquisa diminui. A pesquisa "LIKE Mill%" ainda pode ser bastante rápida - o SQL Server pode usar um índice nessa coluna, se houver. A pesquisa "LIKE% expression%" é terrivelmente lenta, pois a única maneira de o SQL Server satisfazer essa pesquisa é fazendo uma verificação completa da tabela. Portanto, tenha cuidado com o seu gosto!

Marc

marc_s
fonte
-1 como não, nem sempre é um pouco mais rápido. Se a coluna for indexada usando% mystring%, há duas ordens de magnitude mais lentas. De fato, qualquer padrão de código que valha a pena ter terá diretrizes rigorosas sobre quando e quando não usar como em qualquer banco de dados maior que um micky mouse.
Cruachan
1
Eu nunca disse que seria um pouco mais lento em todos os casos - eu disse que seria um pouco mais lento se você procurar uma correspondência EXATA. É claro que pesquisar com LIKE e usar caracteres curinga, especialmente no início e no final do item de pesquisa, é MUITO mais lento, sem dúvida.
marc_s
E sim, eu concordo - é preciso ter diretrizes claras sobre quando usar o LIKE ou não (somente quando você PRECISA pesquisar com caracteres curinga). Mas, novamente - em teoria, não há diferença entre teoria e prática, mas na prática .......
marc_s
6

Usar = evita caracteres curinga e conflitos de caracteres especiais na cadeia quando você cria a consulta em tempo de execução.

Isso facilita a vida do programador por não ter que escapar de todos os caracteres curinga especiais que podem aparecer na cláusula LIKE e por não produzir o resultado pretendido. Afinal, = é o cenário de caso de uso de 99%, seria uma dor ter que escapar deles sempre.

revira os olhos nos anos 90

Também suspeito que seja um pouco mais lento, mas duvido que seja significativo se não houver curingas no padrão.

Coincoin
fonte
6

Para abordar a questão original sobre desempenho, ela se resume à utilização do índice . Quando ocorre uma simples varredura de tabela, "LIKE" e "=" são idênticos . Quando os índices estão envolvidos, isso depende de como a cláusula LIKE é formada. Mais especificamente, qual é a localização dos caracteres curinga?


Considere o seguinte:

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

Também pode haver diferença insignificante na criação do plano de consulta ao usar "=" vs "LIKE".

Laramie
fonte
4

Além dos curingas, a diferença entre =AND LIKEdependerá do tipo de servidor SQL e do tipo de coluna.

Veja este exemplo:

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 '
  • Usando o MS SQL Server 2012 , os espaços à direita serão ignorados na comparação, exceto LIKEquando o tipo de coluna for VARCHAR.

  • Usando o MySQL 5.5 , os espaços à direita serão ignorados para =, mas não para LIKE, ambos com CHARe VARCHAR.

  • Usando o PostgreSQL 9.1 , os espaços são significativos com ambos =e LIKEusando VARCHAR, mas não com CHAR(consulte a documentação ).

    O comportamento com LIKEtambém difere com CHAR.

    Usar os mesmos dados acima, usar um explícito CASTno nome da coluna também faz a diferença :

    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)

    Isso retorna apenas linhas para "CAST both" e "CAST col".

Bruno
fonte
2

A palavra-chave LIKE, sem dúvida, vem com uma "etiqueta de preço de desempenho" anexada. Dito isto, se você tiver um campo de entrada que possa incluir caracteres curinga para serem usados ​​em sua consulta, recomendo usar LIKE apenas se a entrada contiver um dos curingas. Caso contrário, use o padrão igual à comparação.

Cumprimentos...

Josh Stodola
fonte
1

Realmente, tudo se resume ao que você deseja que a consulta faça. Se você quer dizer uma correspondência exata, use =. Se você quer dizer uma partida mais confusa, use LIKE. Dizer o que você quer dizer geralmente é uma boa política com código.

não não
fonte
1

No Oracle, um 'like' sem curingas retornará o mesmo resultado que um 'igual', mas poderá exigir processamento adicional. De acordo com Tom Kyte , a Oracle tratará um 'like' sem curingas como 'igual' ao usar literais, mas não ao usar variáveis ​​de ligação.

Chris B
fonte
0

=e LIKEnão é o mesmo;

  1. = corresponde à string exata
  2. LIKE corresponde a uma sequência que pode conter caracteres curinga (%)
baretta
fonte
2
Resposta insuficiente
Ele poderia ser usado sem caracteres curinga. A pergunta fazia a diferença para os mesmos casos.
M-Razavi