SQL 'like' vs '=' rendimiento

82

Esta pregunta bordea lo que me pregunto, pero las respuestas no lo abordan exactamente.

Parecería que, en general, '=' es más rápido que 'me gusta' cuando se utilizan comodines. Esta parece ser la sabiduría convencional. Sin embargo, supongamos que tengo una columna que contiene un número limitado de diferentes identificadores varchar fijos, codificados, y quiero seleccionar todas las filas que coincidan con uno de ellos:

select * from table where value like 'abc%'

y

select * from table where value = 'abcdefghijklmn'

'Me gusta' solo debería necesitar probar los primeros tres caracteres para encontrar una coincidencia, mientras que '=' debe comparar toda la cadena. En este caso, me parecería que "me gusta" tendría una ventaja, en igualdad de condiciones.

Esto está pensado como una pregunta académica general, por lo que no debería importar qué base de datos, pero surgió con SQL Server 2005.

MickeyfAgain_BeforeSalirOfSO
fuente
23
Una cosa importante que omitió es si valueestá indexada o no . Si es así, entonces =es una búsqueda simple sin necesidad de escanear la tabla y le quitará los pantalones a cualquier LIKEdeclaración que le arroje.
Daniel DiPaolo
7
@Daniel Creo que eso es incorrecto. A LIKEcon un comodín al final es SARGable y, por lo tanto, realizará una búsqueda de rango en un índice, sin escaneo de tabla a la vista. Esa búsqueda de rango puede competir muy fácilmente con una =declaración y, en muchos casos (como si todas las filas satisfactorias estuvieran en una página, una condición no poco probable) podría tener exactamente el mismo rendimiento, lo que implica el mismo número de lecturas.
ErikE
Mi "en igualdad de condiciones" tenía la intención de cubrir el tema de "indexado o no", pero parece haber al menos cierta controversia sobre cuánta diferencia haría eso, según mis comentarios sobre las otras respuestas.
MickeyfAgain_BeforeSalirOfSO
Mira mi respuesta. Inicialmente probé sin indexar y el rendimiento es idéntico (ambos escaneos de tablas fueron exactamente iguales). Asumí para mi escenario de prueba que estaría indexado, de lo contrario, ¿por qué le importaría el rendimiento?
JNK
5
Toda la charla de "me gusta" en esta pregunta y las respuestas nos hace sonar como un grupo de chicas de secundaria. Como, totalmente.
JulianR

Respuestas:

64

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

Cita desde allí:

las reglas para el uso de índices con LIKE son vagamente así:

  • Si su criterio de filtro usa igual a = y el campo está indexado, lo más probable es que use una BÚSQUEDA DE ÍNDICE / ÍNDICE CLUSTER

  • Si su criterio de filtro usa LIKE, sin comodines (como si tuviera un parámetro en un informe web que PODRÍA tener un%, pero en su lugar usa la cadena completa), es tan probable que el # 1 use el índice. El aumento de costo es casi nada.

  • Si su criterio de filtro usa LIKE, pero con un comodín al principio (como en Name0 LIKE '% UTER'), es mucho menos probable que use el índice, pero aún puede realizar al menos un ESCANEO DE ÍNDICE en un rango completo o parcial de El índice.

  • SIN EMBARGO, si su criterio de filtro usa LIKE, pero comienza con una STRING FIRST y tiene comodines en algún lugar DESPUÉS de eso (como en Name0 LIKE 'COMP% ER'), entonces SQL puede usar INDEX SEEK para encontrar rápidamente filas que tengan lo mismo primero caracteres iniciales y luego busque en esas filas una coincidencia exacta.

(También tenga en cuenta que es posible que el motor SQL todavía no use un índice de la forma que espera, dependiendo de qué más está sucediendo en su consulta y a qué tablas se está uniendo. El motor SQL se reserva el derecho de reescribir su consulta un poco para obtener los datos de la manera que crea que es más eficiente y que puede incluir un INDEX SCAN en lugar de una INDEX SEEK)

BonyT
fuente
1
ese enlace está muerto
baxx
2
@baxx una copia del enlace está disponible en la máquina wayback. web.archive.org/web/20150209022016/http://myitforum.com/cs2/…
alphabet5
45

Es una diferencia medible.

Ejecute lo siguiente:

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)

Entonces:

SET SHOWPLAN_XML ON

Entonces:

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

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

El plan de ejecución resultante le muestra que el costo de la primera operación, la LIKEcomparación, es aproximadamente 10 veces más caro que la =comparación.

Si puede utilizar una =comparación, hágalo.

JNK
fuente
2
+1 por probarlo. Sin embargo, es posible que solo mirar el plan de exhibición no cuente toda la historia. Voy a hacer algunas de mis propias pruebas y les haré saber a todos si encuentro algo inesperado.
Tom H
1
Tom: cierto, pero me dio una indicación suficiente de que los dos NO fueron procesados ​​de la misma manera detrás de escena.
JNK
1
Los costos que se muestran en el plan de ejecución son incorrectos. No reflejan el rendimiento real. En el primer plan, se basan en un recuento estimado de filas de los 19.95costos de SQL Server en 19 búsquedas clave adicionales que nunca se materializan en la actualidad (incluso en el plan de ejecución real , los costos que se muestran se basan en el costo estimado del subárbol )
Martin Smith
Acabo de hacer su prueba y una con aproximadamente 1 millón de filas y, en ambos casos, el rendimiento y los planes de consulta fueron idénticos. Esto es en SQL 2008 ya que no tengo 2005 en esta máquina.
Tom H
1
@JNK - lo acabo de probar - hay una diferencia insignificante, sin embargo, la disparidad es la misma. 327ms para LIKE, 203ms para =. Espero que si ejecutara más pruebas y tomara promedios precisos, no habría una diferencia real entre #temp y la tabla real.
Will A
13

También debe tener en cuenta que, al usar like, algunos tipos de SQL ignorarán los índices y eso matará el rendimiento. Esto es especialmente cierto si no usa el patrón "comienza con" como en su ejemplo.

Realmente debería mirar el plan de ejecución de la consulta y ver qué está haciendo, adivinar lo menos posible.

Dicho esto, el patrón "comienza con" puede y está optimizado en el servidor SQL. Se va a utilizar el índice de la tabla. EF 4.0 cambió a likepara StartsWithpor esta misma razón.

Blindy
fuente
2
Ninguna base de datos relacional que se precie ignorará un índice cuando el patrón similar sea parte de la consulta y el comodín esté al final. Esa puede ser una historia diferente si está vinculando el valor y la base de datos admite la vinculación separada de la preparación de la consulta.
Dave W. Smith
Eso es lo que mi instinto me dice también, pero solo tengo experiencia práctica con el servidor SQL a este respecto, así que me concentré en eso específicamente.
Blindy
7

Si valueno está indexado, ambos dan como resultado un escaneo de tabla. La diferencia de rendimiento en este escenario será insignificante.

Si valueestá indexado, como señala Daniel en su comentario, =dará como resultado una búsqueda de índice que es el rendimiento O (log N). El LIKE (lo más probable, dependiendo de qué tan selectivo sea) dará como resultado un escaneo parcial del índice >= 'abc'y < 'abd'requerirá más esfuerzo que el =.

Tenga en cuenta que estoy hablando de SQL Server aquí, no todos los DBMS serán buenos con LIKE.

Will A
fuente
No creo que sepas cómo funciona la búsqueda binaria. Tanto el =caso como el like '...%'caso se comportan de la misma manera si sql reconoce el patrón (y lo hace), porque en ambos casos los subárboles se eligen en base a relaciones de comparación.
Blindy
Oh, lo hago. Lo más probable es que LIKE se comporte peor, aunque seguirá siendo O (log N) si la selectividad es lo suficientemente alta: O (log N) para averiguar desde dónde comenzar el escaneo parcial, luego varias lecturas hacia adelante a través del índice hasta 'abd'se alcanza el punto final .
Será un
Sí, pero el ejemplo del OP supone que solo hay un valor en ese rango, por lo que con eso en mente, las comparaciones serán idénticas.
Blindy
Punto válido: no está completamente claro si esto es lo que decía el OP, pero creo que es más probable que sea el caso. En ese caso, el rendimiento será prácticamente idéntico.
Será un
La búsqueda de rango de un LIKE probablemente competirá con bastante facilidad con una instrucción =, y en muchos casos (como si todas las filas satisfactorias estuvieran en una página, una condición no poco probable) podría tener exactamente el mismo rendimiento, lo que implica el mismo número de lecturas . Creo que decir "requerirá más esfuerzo" es una afirmación general errónea.
ErikE
5

Estás haciendo la pregunta incorrecta. En las bases de datos no es el rendimiento del operador lo que importa, es siempre la SARGability de la expresión y la cobertura de la consulta general. El desempeño del propio operador es en gran parte irrelevante.

Entonces, ¿cómo comparar LIKEy =comparar en términos de SARGability? LIKE, cuando se usa con una expresión que no comienza con una constante (por ejemplo, cuando se usa LIKE '%something'), por definición no es SARGabale. ¿Pero eso hace =o LIKE 'something%'SARGable? No. Al igual que con cualquier pregunta sobre el rendimiento de SQL, la respuesta no está en la consulta del texto, sino en el esquema implementado. Estas expresiones pueden ser SARGable si existe un índice para satisfacerlas.

Entonces, a decir verdad, hay pequeñas diferencias entre =y LIKE. Pero preguntar si un operador u otro operador es "más rápido" en SQL es como preguntar "¿Qué va más rápido, un coche rojo o un coche azul?". Debería hacer preguntas sobre el tamaño del motor y el peso del vehículo, no sobre el color ... Para abordar las preguntas sobre la optimización de tablas relacionales, el lugar para buscar son sus índices y sus expresiones en la cláusula WHERE (y otras cláusulas, pero generalmente comienza con el DÓNDE).

Remus Rusanu
fuente
5

Un ejemplo personal usando mysql 5.5: tenía una combinación interna entre 2 tablas, una de 3 millones de filas y una de 10 mil filas.

Al usar un me gusta en un índice como se muestra a continuación (sin comodines), tomó aproximadamente 30 segundos:

where login like '12345678'

usando 'explicar' obtengo:

ingrese la descripción de la imagen aquí

Al usar un '=' en la misma consulta, tomó alrededor de 0.1 segundos:

where login ='600009'

Usando 'explicar' obtengo:

ingrese la descripción de la imagen aquí

Como puede ver, la likebúsqueda de índice canceló por completo, por lo que la consulta tomó 300 veces más tiempo.

Aris
fuente
También puede simplemente mirar el plan de ejecución para confirmar esto
LittleBobbyTables - Au Revoir
gracias @LittleBobbyTables. Echaré un vistazo a eso.
Aris
No sé si se debe a mi versión reciente (5.7), pero LIKE no rompe mi índice único aquí.
Sebas
0

Quizás esté buscando una búsqueda de texto completo .

A diferencia de la búsqueda de texto completo, el predicado LIKE Transact-SQL solo funciona en patrones de caracteres. Además, no puede utilizar el predicado LIKE para consultar datos binarios formateados. Además, una consulta LIKE contra una gran cantidad de datos de texto no estructurados es mucho más lenta que una consulta equivalente de texto completo contra los mismos datos . Una consulta LIKE contra millones de filas de datos de texto puede tardar minutos en devolverse; mientras que una consulta de texto completo puede tomar solo unos segundos o menos con los mismos datos, dependiendo del número de filas que se devuelvan.


fuente
-1

Lo primero es lo primero ,

no siempre son iguales

    select 'Hello' from dual where 'Hello  ' like 'Hello';

    select 'Hello' from dual where 'Hello  ' =  'Hello';

cuando las cosas no siempre son iguales, hablar de su desempeño no es tan relevante.

Si está trabajando con cadenas y solo variables de caracteres, puede hablar sobre el rendimiento. Pero no use like y "=" como si fueran generalmente intercambiables.

Como habrá visto en muchas publicaciones (anteriores y otras preguntas), en los casos en que son iguales, el rendimiento de Me gusta es más lento debido a la coincidencia de patrones (intercalación)

usuario5190021
fuente
Si 'Hello 'es un VARCHAR(predeterminado), está en lo correcto, pero si es un, CHARno lo está. Transfiéralo a ay CHAR(7)ambos devuelven verdadero. Además, ¿qué diablos estás haciendo donde no TRIMestás usando tus varchars? (nota: este es al menos el caso en SQL Server 2008r2)
abluejelly