IN vs OR en la cláusula SQL WHERE

150

Cuando se trata de grandes bases de datos, ¿cuál funciona mejor, INo ORen la Wherecláusula SQL ?

¿Hay alguna diferencia en la forma en que se ejecutan?

felix
fuente
Mi primera suposición sería que OR funciona mejor, a menos que el motor SQL convierta IN en OR detrás de escena. ¿Has visto el plan de consulta de estos dos?
Raj
Posible duplicado del rendimiento MYSQL OR vs IN
Steve Chambers

Respuestas:

170

Supongo que quiere saber la diferencia de rendimiento entre los siguientes:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

Según el manual de MySQL, si los valores son constantes, INordena la lista y luego utiliza una búsqueda binaria. Me imagino que los ORevalúa uno por uno sin ningún orden en particular. Entonces INes más rápido en algunas circunstancias.

La mejor manera de saber es perfilar ambos en su base de datos con sus datos específicos para ver cuál es más rápido.

Probé ambos en un MySQL con 1000000 filas. Cuando se indexa la columna, no hay una diferencia apreciable en el rendimiento: ambos son casi instantáneos. Cuando la columna no está indexada obtuve estos resultados:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Entonces, en este caso, el método que usa OR es aproximadamente un 30% más lento. Agregar más términos aumenta la diferencia. Los resultados pueden variar en otras bases de datos y en otros datos.

Mark Byers
fuente
20
Si el optimizador vale la pena, deben realizar lo mismo.
Janick Bernet
27
@inflagranti: Desafortunadamente, ningún optimizador es perfecto. Los optimizadores son programas extremadamente complejos y cada implementación tendrá sus propias fortalezas y debilidades. Es por eso que digo que debe perfilar una implementación específica. Me imagino que la estructura adicional del INmétodo hace que sea más fácil de optimizar que un montón de ORcláusulas posiblemente relacionadas . Me sorprendería si hay un motor donde el ORmétodo es más rápido, pero no me sorprende que haya momentos en que OR sea más lento.
Mark Byers
2
@MarkByers ¿No podría el optimizador siempre sustituir múltiples ORs con un IN?
tymtam
36

La mejor manera de averiguarlo es mirando el Plan de ejecución.


Lo probé con Oracle , y fue exactamente lo mismo.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Aunque la consulta usa IN, el Plan de ejecución dice que usa OR:

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

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

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              
Peter Lang
fuente
1
¿Qué sucede en Oracle si tiene más de 3 valores que está probando? ¿Sabe si Oracle no puede realizar la misma optimización de búsqueda binaria que MySQL o lo hace en ambos casos?
Mark Byers
2
@ Mark Byers: Intenté la misma consulta con 10 valores, todavía el mismo resultado. Tenga en cuenta que el optimizador recurrió a mis valores en orden alfabético. No me sorprendería si Oracle hiciera alguna optimización interna de ese filtro ...
Peter Lang
55
Oracle también tiene una INLIST ITERATORoperación, que seleccionaría si hubiera un índice que pudiera usar. Aún así, cuando lo probé, tanto INy ORterminar con el mismo plan de ejecución.
Cheran Shunmugavel
7

El operador OR necesita un proceso de evaluación mucho más complejo que la construcción IN porque permite muchas condiciones, no solo iguales a IN.

Aquí hay un ejemplo de lo que puede usar con OR pero que no es compatible con IN: mayor. mayor o igual, menor, menor o igual, ME GUSTA y algunos más como el oráculo REGEXP_LIKE. Además, considere que las condiciones no siempre pueden comparar el mismo valor.

Para el optimizador de consultas, es más fácil administrar el operador IN porque es solo una construcción que define el operador OR en múltiples condiciones con = operador en el mismo valor. Si usa el operador OR, el optimizador puede no considerar que siempre está usando el operador = en el mismo valor y, si no realiza una elaboración más profunda y mucho más compleja, probablemente podría excluir que solo haya = operadores para los mismos valores en todas las condiciones involucradas, con la consiguiente exclusión de métodos de búsqueda optimizados como la búsqueda binaria ya mencionada.

[EDITAR] Probablemente un optimizador puede no implementar el proceso de evaluación IN optimizado, pero esto no excluye que una vez podría suceder (con una actualización de la versión de la base de datos). Entonces, si usa el operador OR, esa elaboración optimizada no se usará en su caso.

Alessandro Rossi
fuente
6

Creo que Oracle es lo suficientemente inteligente como para convertir el menos eficiente (lo que sea) en el otro. Así que creo que la respuesta debería depender de la legibilidad de cada uno (donde creo que INclaramente gana)

soulmerge
fuente
2

ORtiene sentido (desde el punto de vista de la legibilidad), cuando hay menos valores para comparar. INes útil especialmente cuando tiene una fuente dinámica, con la que desea comparar los valores.

Otra alternativa es usar a JOINcon una tabla temporal.
No creo que el rendimiento deba ser un problema, siempre que tenga los índices necesarios.

shahkalpesh
fuente
-2

Hice una consulta SQL en una gran cantidad de OR (350). Postgres lo hace 437.80ms .

Use OR

Ahora usa IN:

Usar en

23,18 ms

user3003962
fuente
44
Eso no es exactamente lo mismo, ya que ha utilizado una subconsulta para la cláusula IN.
gliljas