2009-10-22 41 views
10

Me pregunto cómo sería el rendimiento de una consulta utilizando la palabra clave LIKE y el comodín como el valor en comparación con tener ninguna cláusula where.SQL LIKE Rendimiento con solo el comodín (%) como valor

Considere una cláusula where como "DONDE un ME GUSTA '%'". Esto coincidirá con todos los valores posibles de la columna 'a'. ¿Cómo se compara esto con no tener la cláusula where en absoluto?

La razón por la que pregunto esto es porque tengo una aplicación donde hay algunos campos en los que el usuario puede especificar valores para buscar. En algunos casos, al usuario le gustaría 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 coincida con todos los posibles valores de a y 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 que coincida con todo? 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 probablemente sea específica de la base de datos. Entonces, 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 consulta comodín:

SELECT * FROM TableName WHERE b LIKE ? 

B es consulta comodín:

SELECT * FROM TableName WHERE a LIKE ? 

A y B son comodines:

SELECT * FROM TableName 

No hay comodines:

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

Obviamente, tener una sola consulta es el más simple y fácil de mantener. Prefiero usar solo una consulta si el rendimiento aún será bueno.

+0

Solo puedo recomendar probarlo. Pero trataría de atenerme a consultas simples. No compliques demasiado, haz dos separados. EN MI HUMILDE OPINIÓN. – Nate

+5

Recomiendo leer el artículo de Erland sobre condiciones dinámicas de búsqueda. Es bastante largo, pero creo que le dará una idea muy seria y valiosa sobre el tema. http://www.sommarskog.se/dyn-search-2005.html –

+1

"Me pregunto cuál sería el rendimiento de una consulta". Una respuesta fácil a eso es: ejecutar algunas pruebas. –

Respuesta

3

Tenía la esperanza de que hubiera una respuesta de libro de texto pero suena al igual que va a variar en gran medida con diferentes tipos de base de datos La mayoría de las respuestas indicaron que debería realizar una prueba, así que eso es exactamente lo que hice.

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

de consulta 1:

SELECT * FROM TableName 

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

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

Consulta 1 Tiempo medio: 178ms

Tiempo medio de consulta 2: 181 ms

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

2

Cualquier DBMS que merezca la pena eliminaría las cláusulas LIKE '%' antes incluso de intentar ejecutar la consulta. Estoy bastante seguro de haber visto que DB2/z hace esto en sus planes de ejecución.

La sentencia preparada no debe marcar la diferencia, ya que debe convertirse en real SQL antes de que llegue al motor de ejecución.

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

sé que las consultas como:

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

son optimizado para eliminar toda la cláusula where antes de la ejecución (en DB2 de todos modos y, antes de preguntar, la construcción es útil cuando es necesario eliminar el efecto de la cláusula where pero aún mantiene el marcador de posición del parámetro (usando BIRT con Javascript para modificar las consultas para comodines)).

+1

No creo que esto sea cierto, especialmente si la columna que se compara es NULLable. LIKE '%' no debe devolver aquellas filas donde la columna es NULL, por lo que quitar los criterios no debería reintroducirlos repentinamente en los resultados. –

+0

El DBMS debería (y es * "* debería") poder decir si la columna no puede contener nulos y por lo tanto no optimizar. En cualquier caso, eso haría que la pregunta de OP sea discutible, ya que tampoco podrían hacer eso. – paxdiablo

1

Dependiendo de cómo está estructurado el predicado LIKE y en el campo que está probando, es posible que necesite un escaneo completo de la tabla. Semánticamente, un '%' puede implicar una exploración completa 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 arroja fuera de la cláusula WHERE?

12

SQL Server generalmente ver

WHERE City LIKE 'A%' 

y tratarlo como

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

... y usar sin problemas una búsqueda de índice en su caso. Digo 'generalmente', porque lo he visto no 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 
+2

DB2 (al menos) tiene el concepto de índices inversos donde '% ville' se optimiza fácilmente (almacenando los valores invertidos en el índice y cambiando internamente la consulta a 'elliv%'). Puede emular lo mismo en otro DBMS 'con una columna adicional e insertar/actualizar activadores. – paxdiablo

+0

Claro, pero luego% ville% se vuelve más complicado. Si busca palabras completas, la búsqueda de FullText se convierte en una opción más agradable. –

+2

+1 para señalar que 'LIKE '%'' solo devolverá filas con valores no nulos. –

4

Usted puede usar cualquier análisis de las ofertas de DBMS (por ejemplo EXPLAIN para MySQL, SET SHOWPLAN_ALL ON para MS SQL (consulta o use uno de los other methods), EXPLAIN PLAN FOR para Oracle) para ver cómo se ejecutará la consulta.

0

¿Qué pasa si una columna tiene un valor en blanco no nulo? Tu consulta probablemente coincida.

Si esta es una consulta para una aplicación del mundo real, intente utilizar las características de indexación de texto libre de la mayoría de las bases de datos sql modernas. Los problemas de rendimiento serán insignificantes.

Un simple si la declaración de si (AB) búsqueda ab otra cosa (A) buscar un bien B búsqueda b demás usuarios dicen que no especificó nada

es trivial para mantener y se vuelve mucho más fácil de entender en lugar de hacer suposiciones sobre el operador LIKE. Probablemente va a hacer eso en la interfaz de usuario de todos modos cuando se muestran los resultados "Su búsqueda de A encontró x" o "Su búsqueda de AB encontró ..."

0

No estoy seguro del valor de usar una declaración preparada con el tipo de parámetros que está describiendo. La razón es que puede 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 era '%'.

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

-2

donde cláusula con "me gusta '%'" como único predicado se comportará exactamente igual que ninguna cláusula where.

+0

Esto está mal, solo los valores no NULL concuerdan. – Thorsten

+0

gracias por la corrección! – user130770

+0

Quise decir que se comportará igual desde la perspectiva del rendimiento, pero obviamente no fue lo suficientemente claro. Además, esto tampoco es cierto en algunos casos. – user130770

2

Derby también ofrece herramientas para examinar el plan de consulta real que se utilizó, por lo que puede ejecutar experimentos con Derby y ver el plan de consulta que eligió Derby. Puede ejecutar Derby con -Dderby.language.logQueryPlan = true, y Derby va a escribir el plan de consulta a derby.log, o puede utilizar la instalación RUNTIMESTATISTICS, como se describe aquí: http://db.apache.org/derby/docs/10.5/tuning/ctundepth853133.html

No estoy seguro de si Derby eliminará el A ME GUSTA '%' antes de tiempo, pero tampoco creo que la presencia de esa cláusula introduzca una gran disminución de la velocidad de ejecución.

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

2

Parece que Oracle 10gR2 no realiza una optimización especial para esta situación, pero reconoce que LIKE '%' excluye los valores 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) 

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

1

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

Por lo tanto:

  • al usar comandos preparados, tienen cuatro estados diferentes disponibles (0, sólo, solamente B, ambos) y utilizar el apropiado cuando sea necesario
  • ver si mejora el rendimiento cuando no usa una declaración preparada cuando se apega a una sola afirmación (aunque sería muy fácil no incluir condiciones "vacías")
Cuestiones relacionadas