Pregunta

Me pregunto cómo sería el rendimiento de una consulta utilizando la palabra clave LIKE y el comodín como valor en comparación con el hecho de no tener ninguna cláusula donde.

Considere una cláusula donde, como " DONDE UN LIKE '%' " Esto coincidirá con todos los valores posibles de la columna 'a'. ¿Cómo se compara esto con no tener la cláusula where?

El motivo por el que pregunto esto es que tengo una aplicación en la que hay algunos campos en los que el usuario puede especificar valores para buscar. En algunos casos, el usuario desea todos los resultados posibles. Actualmente estoy usando una sola consulta como esta:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Los valores de '%' y '%' se pueden suministrar para que coincidan con todos los valores posibles para a y o b. Esto es conveniente ya que puedo usar una única consulta con nombre en mi aplicación para esto. Me pregunto cuáles son las consideraciones de rendimiento para esto. ¿El optimizador de consultas reduce LIKE '%' para simplemente hacer coincidir todos? Me doy cuenta de que porque estoy usando una consulta con nombre (declaración preparada), eso también puede afectar la respuesta. Me doy cuenta de que la respuesta es probablemente específica de la base de datos. Específicamente, ¿cómo funcionaría esto en Oracle, MS SQL Server y Derby?

El enfoque alternativo a esto sería utilizar 3 consultas separadas basadas en el usuario que ingresa el comodín.

A es una consulta comodín:

SELECT * FROM TableName WHERE b LIKE ?

B es una consulta comodín:

SELECT * FROM TableName WHERE a LIKE ?

A y B son comodines:

SELECT * FROM TableName

No hay comodines:

<*>

Obviamente, tener una sola consulta es lo más sencillo y fácil de mantener. Preferiría usar solo una consulta si el rendimiento seguirá siendo bueno.

¿Fue útil?

Solución 3

Esperaba que hubiera una respuesta de libro de texto para esto, pero parece que variará en gran medida con los diferentes tipos de bases de datos. La mayoría de las respuestas indicaron que debería realizar una prueba para que sea exactamente lo que hice.

Mi aplicación se dirige principalmente a las bases de datos Derby, MS SQL y Oracle. Dado que derby se puede ejecutar integrado y es fácil de configurar, primero probé el rendimiento. Los resultados fueron sorprendentes. Probé el peor de los casos contra una tabla bastante grande. Corrí la prueba 1000 veces y promedié los resultados.

Consulta 1:

SELECT * FROM TableName

Consulta 2 (con valores de a = "% " y b = "% "):

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Tiempo promedio de la consulta 1: 178ms

Tiempo promedio de la consulta 2: 181 ms

Por lo tanto, el rendimiento en derby es casi el mismo entre las dos consultas.

Otros consejos

SQL Server generalmente verá

WHERE City LIKE 'A%'

y tratarlo como

WHERE City >= 'A' AND City < 'B'

... y felizmente use una búsqueda de índice si es apropiado. Digo "en general", porque he visto que no logra hacer esta simplificación en ciertos casos.

Si alguien está tratando de hacer:

WHERE City LIKE '%ville'

... entonces una búsqueda de índice será esencialmente imposible.

Pero algo tan simple como:

WHERE City LIKE '%'

se considerará equivalente a:

WHERE City IS NOT NULL

Puede utilizar cualquier análisis de consulta que ofrezca el DBMS (por ejemplo, EXPLAIN para MySQL, SET SHOWPLAN_ALL ON para MS SQL (o use uno de los otros métodos ), EXPLAIN PLAN FOR para Oracle) para ver cómo se ejecutará la consulta.

Cualquier DBMS que valga la pena perdería las cláusulas LIKE '%' antes de intentar ejecutar la consulta. Estoy bastante seguro de que he visto a DB2 / z hacer esto en sus planes de ejecución.

La declaración preparada no debería hacer una diferencia, ya que debe convertirse en real SQL antes de que llegue al motor de ejecución.

Pero, al igual que con todas las preguntas de optimización, mida, ¡no adivine ! Los DBA existen porque ajustan constantemente el DBMS en función de los datos reales (que cambian con el tiempo). Como mínimo, debe programar (y obtener los planes de ejecución) todas las variaciones con datos estáticos adecuados para ver si hay alguna diferencia.

Sé que consultas como:

select c from t where ((1 = 1) or (c = ?))

están optimizados para eliminar toda la cláusula where antes de la ejecución (de todos modos en DB2 y, antes de que preguntes, la construcción es útil cuando necesitas eliminar el efecto de la cláusula where pero aún así mantener el parámetro marcador de posición (utilizando BIRT con Javascript para modificar las consultas de comodines)).

Derby también ofrece herramientas para examinar el plan de consulta real que se usó, para que pueda realizar experimentos usando Derby y ver el plan de consulta que Derby eligió. Puede ejecutar Derby con -Dderby.language.logQueryPlan = true, y Derby escribirá el plan de consulta en derby.log, o puede usar la función RUNTIMESTATISTICS, como se describe aquí: http://db.apache.org/derby/docs/10.5/tuning/ctundepth853133.html

No estoy seguro de si Derby eliminará A LIKE '%' antes de tiempo, pero tampoco creo que la presencia de esa cláusula vaya a introducir una gran desaceleración en la velocidad de ejecución.

Me gustaría ver el resultado real del plan de consulta que obtienes en tu entorno, con y sin la cláusula A LIKE '%' en su lugar.

Parece que Oracle 10gR2 no realiza una optimización especial para esta situación, pero reconoce que LIKE '%' excluye nulos.

create table like_test (col1)
as select cast(dbms_random.string('U',10) as varchar2(10))
from dual
connect by level <= 1000
/
insert into like_test values (null)
/
commit
/

exec dbms_stats.gather_table_stats(user,'like_test')

explain plan for
select count(*)
from   like_test
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 like '%'
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 is not null
/
select plan_table_output from table(dbms_xplan.display)
/

... dando ...

Plan hash value: 3733279756

------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |            |          |
|   2 |   TABLE ACCESS FULL| LIKE_TEST |  1001 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------

... y ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" LIKE '%')

... y ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" IS NOT NULL)

Tenga en cuenta la cardinalidad (filas) en la línea TABLE ACCESS FULL

Dependiendo de cómo esté estructurado el predicado LIKE y del campo en el que esté realizando la prueba, es posible que necesite un escaneo completo de la tabla. Semánticamente, un '%' puede implicar un escaneo completo de la tabla, pero el Servidor SQL realiza todo tipo de optimización internamente en las consultas. Entonces la pregunta es: ¿Sql Server optimiza en un predicado LIKE formado con '%' y lo elimina de la cláusula WHERE?

Un aspecto que creo que falta en la discusión es el hecho de que el OP desea utilizar una declaración preparada. En el momento en que se prepare la declaración, la base de datos / optimizador no podrá resolver las simplificaciones que otros han mencionado, por lo que no podrá optimizar el a like '%' como el valor real. el valor no se conocerá en el momento de la preparación.

Por lo tanto:

  • cuando use declaraciones preparadas, tenga cuatro declaraciones diferentes disponibles (0, solo a, solo b, ambas) y use la apropiada cuando sea necesario
  • vea si obtiene un mejor rendimiento cuando no usa una declaración preparada cuando se adhiere a una sola declaración (aunque sería bastante fácil no incluir las condiciones 'vacías')

¿Qué sucede si una columna tiene un valor en blanco que no sea nulo? Su consulta probablemente coincidirá.

Si se trata de una consulta para una aplicación del mundo real, intente usar las funciones de indización de texto gratuitas de la mayoría de las bases de datos SQL modernas. Los problemas de rendimiento serán insignificantes.

Una declaración simple de si (A B)  buscar una b otro (A)  buscar un otra cosa B  buscar b más  Dígale al usuario que no especificaron nada

es trivial de mantener y se vuelve mucho más fácil de entender en lugar de hacer suposiciones sobre el operador LIKE. Probablemente lo va a hacer en la interfaz de usuario cuando muestre los resultados " Su búsqueda de A x encontrada " o " Su búsqueda de A B encontrado ... "

No estoy seguro del valor de usar una declaración preparada con el tipo de parámetros que estás describiendo. La razón es que podría engañar al optimizador de consultas para que prepare un plan de ejecución que sería completamente incorrecto dependiendo de cuál de los parámetros fuera '%'.

Por ejemplo, si la declaración se preparó con un plan de ejecución usando el índice en la columna A, pero el parámetro para la columna A resultó ser '%', puede que tenga un bajo rendimiento.

una cláusula where con " como '%' " como el único predicado se comportará exactamente igual que ninguna cláusula where en absoluto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top