¿Diferencia entre EXISTA e IN en SQL?

443

¿Cuál es la diferencia entre la cláusula EXISTSy INen SQL?

¿Cuándo debemos usar EXISTSy cuándo debemos usar IN?

Krantz
fuente

Respuestas:

224

La existspalabra clave se puede usar de esa manera, pero en realidad está destinada a evitar contar:

--this statement needs to check the entire table
select count(*) from [table] where ...

--this statement is true as soon as one match is found
exists ( select * from [table] where ... )

Esto es más útil cuando tiene ifdeclaraciones condicionales, ya que existspuede ser mucho más rápido que count.

Se inutiliza mejor cuando tiene que pasar una lista estática:

 select * from [table]
 where [field] in (1, 2, 3)

Cuando tiene una tabla en una indeclaración, tiene más sentido usar a join, pero sobre todo no debería importar. El optimizador de consultas debe devolver el mismo plan de cualquier manera. En algunas implementaciones (en su mayoría antiguas, como Microsoft SQL Server 2000), las inconsultas siempre obtendrán un plan de unión anidado , mientras que las joinconsultas usarán anidado, fusión o hash según corresponda. Las implementaciones más modernas son más inteligentes y pueden ajustar el plan incluso cuando inse usa.

Keith
fuente
2
¿Podría dar más detalles sobre "Cuando tiene una tabla en una declaración in, tiene más sentido usar una combinación, pero realmente no importa. El optimizador de consultas devolverá el mismo plan de cualquier manera"? No es la parte del optimizador de consultas, la parte en la que puede usar a JOINcomo reemplazo IN.
farthVader
select * from [table] where [field] in (select [field] from [table2])devuelve los mismos resultados (y plan de consulta) que select * from [table] join [table2] on [table2].[field] = [table].[field].
@Sander no lo hace: la primera consulta devuelve todas las columnas de table, mientras que la segunda devuelve todo de tabley table2. En algunas bases de datos SQL (en su mayoría antiguas), la inconsulta se implementará como una unión anidada, mientras que la joinconsulta se puede anidar, fusionar, aplicar hash, etc., lo que sea más rápido.
Keith
2
De acuerdo, debería haber especificado columnas en la cláusula select, pero debe actualizar su respuesta porque establece claramente que las consultas "devolverán el mismo plan de cualquier manera".
existsse puede usar dentro de una declaración de caso, por lo que también pueden ser útiles de esa manera, es decirselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie
125

EXISTSle dirá si una consulta arrojó algún resultado. p.ej:

SELECT * 
FROM Orders o 
WHERE EXISTS (
    SELECT * 
    FROM Products p 
    WHERE p.ProductNumber = o.ProductNumber)

IN se usa para comparar un valor con varios, y puede usar valores literales, como este:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (1, 10, 100)

También puede usar los resultados de la consulta con la INcláusula, como esta:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)
Matt Hamilton
fuente
3
La última consulta es peligrosa porque puede fallar en el caso de que la subconsulta no devuelva ningún resultado. La cláusula 'in' requiere al menos 1 argumento ...
user2054927
40
@ user2054927 La última consulta no devolverá correctamente filas si la subconsulta no devuelve filas, ¡no hay nada peligroso en eso!
Tony Andrews
La mejor respuesta
Aminadav Glickshtein
81

Basado en el optimizador de reglas :

  • EXISTSes mucho más rápido que INcuando los resultados de la subconsulta son muy grandes.
  • INes más rápido que EXISTScuando los resultados de la subconsulta son muy pequeños.

Basado en el optimizador de costos :

  • No hay diferencia.
Jackson
fuente
21
¿Prueba de tu argumento? ¡No creo que IN sea más rápido que EXISTE!
Nawaz
22
@Nawaz ¿Qué tal la prueba de por qué IN siempre es más lento que EXISTS?
ceving
2
¿Optimizador de consultas mal implementado? Parece que algo así (aunque no exactamente esta situación) suceda en ciertos RDBM ...
Haroldo_OK
1
EXISTS devuelve valores puramente booleanos, que siempre son más rápidos que tener que comparar cadenas o valores más grandes que un tipo BIT / Boolean. IN puede o no ser una comparación booleana. Como la programación prefiere el uso EXPLÍCITO para la estabilidad (parte de ACID), generalmente se prefiere EXISTO.
clifton_h
2
¿Por qué se votó esto tantas veces? No hay absolutamente ninguna razón por la cual esta afirmación basada en suposiciones sea generalmente cierta.
Lukas Eder
40

Supongo que sabe lo que hacen y, por lo tanto, se usan de manera diferente, por lo que entenderé su pregunta como: ¿Cuándo sería una buena idea reescribir el SQL para usar IN en lugar de EXISTS, o viceversa?

¿Es eso una suposición justa?


Editar : La razón por la que pregunto es que, en muchos casos, puede reescribir un SQL basado en IN para usar EXISTS, y viceversa, y para algunos motores de base de datos, el optimizador de consultas tratará los dos de manera diferente.

Por ejemplo:

SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

puede reescribirse a:

SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

o con una combinación:

SELECT Customers.*
FROM Customers
    INNER JOIN Orders ON Customers.ID = Orders.CustomerID

Entonces mi pregunta sigue en pie: ¿el póster original se pregunta qué hace IN y EXISTS y, por lo tanto, cómo usarlo, o pregunta si reescribir un SQL usando IN para usar EXISTS, o viceversa, será una buena idea?

Lasse V. Karlsen
fuente
12
No sé sobre el OP, ¡pero me gustaría la respuesta a esta pregunta! ¿Cuándo debo usar EXISTS en lugar de IN con una subconsulta que devuelve ID?
Roy Tinker
8
en el JOIN, necesitarás unDISTINCT
Jaider
44
gran demostración, pero prácticamente deja la pregunta sin respuesta
Junchen Liu
28
  1. EXISTSes mucho más rápido que INcuando los resultados de la subconsulta son muy grandes.
    INes más rápido que EXISTScuando los resultados de la subconsulta son muy pequeños.

    CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
    GO
    CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
    GO
    
    INSERT INTO t1
    SELECT 1, 'title 1', 5 UNION ALL
    SELECT 2, 'title 2', 5 UNION ALL
    SELECT 3, 'title 3', 5 UNION ALL
    SELECT 4, 'title 4', 5 UNION ALL
    SELECT null, 'title 5', 5 UNION ALL
    SELECT null, 'title 6', 5
    
    INSERT INTO t2
    SELECT 1, 1, 'data 1' UNION ALL
    SELECT 2, 1, 'data 2' UNION ALL
    SELECT 3, 2, 'data 3' UNION ALL
    SELECT 4, 3, 'data 4' UNION ALL
    SELECT 5, 3, 'data 5' UNION ALL
    SELECT 6, 3, 'data 6' UNION ALL
    SELECT 7, 4, 'data 7' UNION ALL
    SELECT 8, null, 'data 8' UNION ALL
    SELECT 9, 6, 'data 9' UNION ALL
    SELECT 10, 6, 'data 10' UNION ALL
    SELECT 11, 8, 'data 11'
  2. Consulta 1

    SELECT
    FROM    t1 
    WHERE   not  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)

    Consulta 2

    SELECT t1.* 
    FROM   t1 
    WHERE  t1.id not in (SELECT  t2.t1id FROM t2 )

    Si en t1su identificación tiene un valor nulo, la Consulta 1 los encontrará, pero la Consulta 2 no puede encontrar los parámetros nulos.

    Es decir IN, no puedo comparar nada con nulo, por lo que no tiene ningún resultado para nulo, pero EXISTSpuede comparar todo con nulo.

Alireza Masali
fuente
Esta respuesta es una sinopsis razonable del sentimiento de Tom Kite ( asktom.oracle.com/pls/asktom/… )
Jeromy French
Creo que esta respuesta se basa en la intuición, lo cual es bastante justo. Pero no puede ser universalmente cierto. Por ejemplo, casi con certeza no es cierto para Ingres , que analizaría las consultas SQL equivalentes para que sean la misma consulta QUEL, que carece de la "riqueza" de SQL, ejem, cuando se trata de escribir lo mismo de varias maneras.
cuando el
Estas 2 consultas son lógicamente equivalentes si y solo si t2.id se define como "NOT NULL". Para otorgar la equivalencia sin dependencia en la definición de la tabla, la segunda consulta debe ser "SELECCIONE t1. * DESDE t1 DONDE t1.id no está en (SELECCIONE t2.id DESDE t2 donde t2.id no es nulo )"
David דודו Markovitz
16

Si está utilizando el INoperador, el motor SQL escaneará todos los registros obtenidos de la consulta interna. Por otro lado, si estamos usando EXISTS, el motor SQL detendrá el proceso de escaneo tan pronto como encuentre una coincidencia.

Si está utilizando la operación IN
fuente
10

IN solo admite relaciones de igualdad (o desigualdad cuando está precedido por NOT ).
Es un sinónimo de = any / = some , p. Ej.

select    * 
from      t1 
where     x in (select x from t2)
;

EXISTS admite tipos de relaciones variantes, que no se pueden expresar con IN , por ejemplo:

select    * 
from      t1 
where     exists (select    null 
                  from      t2 
                  where     t2.x=t1.x 
                        and t2.y>t1.y 
                        and t2.z like '℅' || t1.z || '℅'
                  )
;

Y en una nota diferente:

El supuesto rendimiento y las diferencias técnicas entre EXISTS e IN pueden ser el resultado de implementaciones / limitaciones / errores específicos del proveedor, pero muchas veces no son más que mitos creados debido a la falta de comprensión de las bases internas de las bases de datos.

La definición de las tablas, la precisión de las estadísticas, la configuración de la base de datos y la versión del optimizador tienen un impacto en el plan de ejecución y, por lo tanto, en las métricas de rendimiento.

David דודו Markovitz
fuente
Vota por tu comentario sobre el rendimiento: sin centrarnos en un DBMS específico, deberíamos asumir que depende del optimizador determinar qué funciona mejor.
Manngo
9

La Existspalabra clave evalúa verdadero o falso, pero la INpalabra clave compara todos los valores en la columna de subconsulta correspondiente. Otro se Select 1puede usar con Existscomando. Ejemplo:

SELECT * FROM Temp1 where exists(select 1 from Temp2 where conditions...)

Pero INes menos eficiente y Existsmás rápido.

Arulraj.M
fuente
5

Yo creo que,

  • EXISTSes cuando necesita hacer coincidir los resultados de la consulta con otra subconsulta. Los resultados de la consulta n. ° 1 deben recuperarse donde coinciden los resultados de SubQuery. Tipo de unión ... Por ejemplo, seleccione la tabla n. ° 1 de los clientes que han realizado pedidos en la tabla n. ° 2

  • IN es recuperar si el valor de una columna específica se encuentra en INuna lista (1,2,3,4,5) Por ejemplo, seleccione clientes que se encuentran en los siguientes códigos postales, es decir, los valores de código postal se encuentran en la lista (...).

Cuándo usar uno sobre el otro ... cuando sienta que se lee apropiadamente (comunica mejor la intención).

Gishu
fuente
4

La diferencia yace aquí:

select * 
from abcTable
where exists (select null)

La consulta anterior devolverá todos los registros, mientras que la siguiente devolverá vacía.

select *
from abcTable
where abcTable_ID in (select null)

Pruébalo y observa la salida.

muchacho rebelde
fuente
1
Hmmm ... Error: [SQL0104] Token) no era válido. En ambos casos. ¿Está asumiendo un RDBMS particular?
jmarkmurphy
3

Según mi conocimiento, cuando una subconsulta devuelve un NULLvalor, se convierte en toda la declaración NULL. En esos casos estamos usando la EXITSpalabra clave. Si queremos comparar valores particulares en subconsultas, entonces estamos usando la INpalabra clave.

RAM
fuente
3

Cuál es más rápido depende del número de consultas obtenidas por la consulta interna:

  • Cuando su consulta interna obtenga miles de filas, EXIST sería una mejor opción
  • Cuando su consulta interna obtenga algunas filas, IN será más rápido

EXIST evalúe en verdadero o falso pero IN compare el valor múltiple. Cuando no sabe que el registro existe o no, debe elegir EXIST

Sumair Hussain Rajput
fuente
3

La razón es que el operador EXISTA funciona según el principio de "al menos encontrado". Devuelve verdadero y detiene la tabla de exploración una vez que se encuentra al menos una fila coincidente.

Por otro lado, cuando el operador IN se combina con una subconsulta, MySQL debe procesar la subconsulta primero y luego utiliza el resultado de la subconsulta para procesar toda la consulta.

La regla general es que si la subconsulta contiene un gran volumen de datos, el operador EXISTA proporciona un mejor rendimiento.

Sin embargo, la consulta que utiliza el operador IN se realizará más rápido si el conjunto de resultados devuelto por la subconsulta es muy pequeño.

Vipin Jain
fuente
1

Entiendo que ambos deberían ser iguales siempre y cuando no estemos tratando con valores NULL.

La misma razón por la cual la consulta no devuelve el valor para = NULL vs es NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

En cuanto al argumento booleano vs comparador, para generar un valor booleano, ambos valores deben compararse y así es como funciona la condición if.Así que no entiendo cómo IN y EXISTS se comportan de manera diferente.

Ranjeeth
fuente
0

Si una subconsulta devuelve más de un valor, es posible que deba ejecutar la consulta externa, si los valores dentro de la columna especificada en la condición coinciden con cualquier valor en el conjunto de resultados de la subconsulta. Para realizar esta tarea, debe usar la inpalabra clave.

Puede usar una subconsulta para verificar si existe un conjunto de registros. Para esto, debe usar la existscláusula con una subconsulta. La existspalabra clave siempre devuelve un valor verdadero o falso.

djohn
fuente
0

Creo que esto tiene una respuesta directa. ¿Por qué no lo compruebas de las personas que desarrollaron esa función en sus sistemas?

Si usted es un desarrollador de MS SQL, aquí está la respuesta directamente de Microsoft.

IN:

Determina si un valor especificado coincide con algún valor en una subconsulta o una lista.

EXISTS:

Especifica una subconsulta para probar la existencia de filas.

Error fatal
fuente
0

Descubrí que usar la palabra clave EXISTS a menudo es muy lento (eso es muy cierto en Microsoft Access). En su lugar, uso el operador de combinación de esta manera: should-i-use-the-keyword-exist-in-sql

Axel Der
fuente
-1

EXISTE es más rápido en rendimiento que IN. Si la mayoría de los criterios de filtro están en subconsulta, entonces es mejor usar IN y si la mayoría de los criterios de filtro están en la consulta principal, mejor usar EXISTS.

Deva
fuente
Esa afirmación realmente no está respaldada por ninguna evidencia, ¿verdad?
Lukas Eder
-2

Si está utilizando el operador IN, el motor SQL escaneará todos los registros obtenidos de la consulta interna. Por otro lado, si estamos usando EXISTS, el motor SQL detendrá el proceso de escaneo tan pronto como encuentre una coincidencia.

Gagandeep Singh
fuente
@ziggy explicar? Esto es más o menos lo que dice la respuesta aceptada. En DEBE verificar cada registro, existe puede detenerse tan pronto como encuentre uno solo.
Ben Thurley
No, no es correcto. INy EXISTSpueden ser equivalentes y transformados entre sí.
Lukas Eder