Diferença entre EXISTS e IN no SQL?

443

Qual é a diferença entre a cláusula EXISTSe INno SQL?

Quando devemos usar EXISTSe quando devemos usar IN?

Krantz
fonte

Respostas:

224

A existspalavra-chave pode ser usada dessa maneira, mas na verdade pretende ser uma maneira de evitar a contagem:

--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 ... )

Isso é mais útil quando você possui ifinstruções condicionais, pois existspode ser muito mais rápido que count.

O iné melhor usado onde você tem uma lista estática para passar:

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

Quando você tem uma tabela em uma indeclaração, faz mais sentido usar a join, mas principalmente isso não deve importar. O otimizador de consulta deve retornar o mesmo plano de qualquer maneira. Em algumas implementações (principalmente mais antigas, como o Microsoft SQL Server 2000), as inconsultas sempre recebem um plano de junção aninhada , enquanto as joinconsultas usam aninhado, mesclagem ou hash, conforme apropriado. Implementações mais modernas são mais inteligentes e podem ajustar o plano mesmo quando inusado.

Keith
fonte
2
Você poderia elaborar "Quando você tem uma tabela em uma declaração, faz mais sentido usar uma junção, mas isso realmente não importa. O otimizador de consulta retornará o mesmo plano de qualquer maneira". Não é a parte do otimizador de consulta, a parte em que você pode usar JOINum substituto IN.
FarthVader
select * from [table] where [field] in (select [field] from [table2])retorna os mesmos resultados (e plano de consulta) que select * from [table] join [table2] on [table2].[field] = [table].[field].
@Sander não: a primeira consulta retorna todas as colunas de table, enquanto a segunda retorna tudo de tablee table2. Em alguns bancos de dados SQL (principalmente antigos), a inconsulta será implementada como uma junção aninhada, enquanto a joinconsulta pode ser aninhada, mesclada, hash etc. - o que for mais rápido.
Keith
2
Ok, eu deveria ter especificado colunas na cláusula select, mas você deve atualizar sua resposta, pois ela afirma claramente que as consultas "retornarão o mesmo plano de qualquer maneira".
existspode ser usado em uma instrução caso, para que eles possam ser útil dessa forma também ieselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie
125

EXISTSinformará se uma consulta retornou algum resultado. por exemplo:

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

IN é usado para comparar um valor a vários e pode usar valores literais, como este:

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

Você também pode usar os resultados da consulta com a INcláusula, assim:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)
Matt Hamilton
fonte
3
A última consulta é perigosa porque pode falhar no caso de a subconsulta não retornar nenhum resultado. A cláusula 'in' requer pelo menos 1 argumento ...
user2054927 01/04
40
@ user2054927 A última consulta não retornará corretamente nenhuma linha se a subconsulta não retornar nenhuma linha - nada de perigoso nisso!
Tony Andrews
A melhor resposta.
Aminadav Glickshtein 04/07/19
81

Com base no otimizador de regras :

  • EXISTSé muito mais rápido do que INquando os resultados da subconsulta são muito grandes.
  • INé mais rápido que EXISTS, quando os resultados da subconsulta são muito pequenos.

Com base no otimizador de custos :

  • Não há diferença.
Jackson
fonte
21
Prova do seu argumento? Eu não acho que o IN seria mais rápido do que EXISTE!
Nawaz
22
@Nawaz Que tal a prova de por que IN é sempre mais lento que EXISTE?
ceving
2
Otimizador de consulta mal implementado? Eu tenho parecer algo como isto (embora não exatamente esta situação) acontecer em certos RDBMs ...
Haroldo_OK
1
EXISTS retorna valores puramente booleanos, sempre mais rápidos do que comparar cadeias ou valores maiores que um tipo BIT / Booleano. IN pode ou não ser uma comparação booleana. Como a programação prefere o uso EXPLICIT por estabilidade (parte do ACID), EXISTS é geralmente preferido.
clifton_h
2
Por que isso foi votado tantas vezes? Não há absolutamente nenhuma razão para que essa declaração baseada em suposições seja geralmente verdadeira.
Lukas Eder
40

Suponho que você saiba o que eles fazem e, portanto, sejam usados ​​de maneira diferente; portanto, entenderei sua pergunta como: Quando seria uma boa idéia reescrever o SQL para usar IN em vez de EXISTS ou vice-versa.

Essa é uma suposição justa?


Edit : O motivo pelo qual estou perguntando é que, em muitos casos, você pode reescrever um SQL com base em IN para usar EXISTS e vice-versa, e para alguns mecanismos de banco de dados, o otimizador de consultas tratará os dois de maneira diferente.

Por exemplo:

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

pode ser reescrito para:

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

ou com uma junção:

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

Portanto, minha pergunta ainda permanece: o pôster original se perguntando o que IN e EXISTS faz e, portanto, como usá-lo, ou ele pergunta se reescrever um SQL usando IN para usar EXISTS, ou vice-versa, será uma boa idéia?

Lasse V. Karlsen
fonte
12
Não sei sobre o OP, mas gostaria de responder a esta pergunta! Quando devo usar EXISTS em vez de IN com uma subconsulta que retorna IDs?
Roy Tinker
8
no JOIN, você precisará de umDISTINCT
Jaider 26/03
4
grande demonstração, mas praticamente deixar a pergunta sem resposta
Junchen Liu
28
  1. EXISTSé muito mais rápido do que INquando os resultados da subconsulta são muito grandes.
    INé mais rápido do que EXISTSquando os resultados da subconsulta são muito pequenos.

    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 )

    Se no t1seu ID tiver valor nulo, a Consulta 1 os encontrará, mas a Consulta 2 não poderá encontrar parâmetros nulos.

    Quero dizer, INnão é possível comparar nada com nulo, portanto, não há resultado para nulo, mas EXISTSpode comparar tudo com nulo.

Alireza Masali
fonte
Esta resposta é sinopse razoável do sentimento de Tom Kite ( asktom.oracle.com/pls/asktom/... )
Jeromy Francês
Eu acho que essa resposta é baseada na intuição, o que é justo o suficiente. Mas não pode ser universalmente verdade. Por exemplo, quase certamente não é verdade para Ingres , que analisaria as duas consultas SQL equivalentes como sendo a mesma consulta QUEL, que carece de 'riqueza' do SQL - ahem - quando se trata de escrever a mesma coisa de várias maneiras.
precisa saber é o seguinte
Essas 2 consultas são logicamente equivalentes se e somente se t2.id for definido como "NOT NULL". Para conceder a equivalência sem dependência na definição da tabela, a 2ª consulta deve ser "SELECT t1. * FROM t1 ONDE t1.id não está em (SELECT t2.id FROM t2 em que t2.id não é nulo )"
David דודו Markovitz
16

Se você estiver usando o INoperador, o mecanismo SQL verificará todos os registros buscados na consulta interna. Por outro lado, se estivermos usando EXISTS, o mecanismo SQL interromperá o processo de verificação assim que encontrar uma correspondência.

Se você estiver usando o operador IN
fonte
10

O IN suporta apenas relações de igualdade (ou desigualdade quando precedido por NOT ).
É sinônimo de = any / = some , por exemplo

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

EXISTS suporta tipos variantes de relações, que não podem ser expressas usando IN , por exemplo:

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 || '℅'
                  )
;

E em uma nota diferente -

As supostas diferenças de desempenho e técnicas entre EXISTS e IN podem resultar de implementações / limitações / bugs de fornecedores específicos, mas muitas vezes eles não passam de mitos criados devido à falta de entendimento interno dos bancos de dados.

A definição das tabelas, a precisão das estatísticas, a configuração do banco de dados e a versão do otimizador têm impacto no plano de execução e, portanto, nas métricas de desempenho.

David Markovitz
fonte
Voto positivo para seu comentário sobre desempenho: sem focar em um DBMS específico, devemos assumir que cabe ao otimizador descobrir o que funciona melhor.
Manngo
9

A Existspalavra-chave avalia true ou false, mas a INpalavra-chave compara todo o valor na coluna correspondente da subconsulta. Outro Select 1pode ser usado com o Existscomando Exemplo:

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

Mas INé menos eficiente e Existsmais rápido.

Arulraj.M
fonte
5

Eu acho que,

  • EXISTSé quando você precisa combinar os resultados da consulta com outra subconsulta. Os resultados da consulta nº 1 precisam ser recuperados onde os resultados da SubQuery correspondem. Tipo de associação .. Por exemplo, selecione a tabela nº 1 dos clientes que também fizeram a tabela nº 2

  • IN é recuperar se o valor de uma coluna específica estiver em INuma lista (1,2,3,4,5). Por exemplo, selecionar clientes que residem nos seguintes códigos postais, ou seja, os valores do código postal estão na lista (....).

Quando usar um sobre o outro ... quando sentir que lê adequadamente (comunica melhor a intenção).

Gishu
fonte
4

A diferença está aqui:

select * 
from abcTable
where exists (select null)

A consulta acima retornará todos os registros, enquanto abaixo um retornaria vazio.

select *
from abcTable
where abcTable_ID in (select null)

Experimente e observe a saída.

rapaz desonesto
fonte
1
Hmmm ... Erro: [SQL0104] Token) não era válido. Em ambos os casos. Você está assumindo um RDBMS específico?
precisa saber é o seguinte
3

Conforme meu conhecimento, quando uma subconsulta retorna um NULLvalor, a declaração inteira se torna NULL. Nesse caso, estamos usando a EXITSpalavra - chave. Se queremos comparar valores específicos em subconsultas, estamos usando a INpalavra - chave.

RAM
fonte
3

Qual deles é mais rápido depende do número de consultas obtidas pela consulta interna:

  • Quando sua consulta interna buscar milhares de linhas, EXIST seria a melhor escolha
  • Quando sua consulta interna buscar algumas linhas, IN será mais rápido

EXISTENTE avalia em verdadeiro ou falso, mas IN compara múltiplos valores. Quando você não sabe que o registro existe ou não, você deve escolher EXIST

Sumair Hussain Rajput
fonte
3

O motivo é que o operador EXISTS trabalha com base no princípio “pelo menos encontrado”. Retorna true e para a verificação da tabela uma vez que pelo menos uma linha correspondente foi encontrada.

Por outro lado, quando o operador IN é combinado com uma subconsulta, o MySQL deve processar a subconsulta primeiro e, em seguida, usa o resultado da subconsulta para processar toda a consulta.

A regra geral é que, se a subconsulta contiver um grande volume de dados, o operador EXISTS fornecerá um melhor desempenho.

No entanto, a consulta que usa o operador IN terá um desempenho mais rápido se o conjunto de resultados retornado da subconsulta for muito pequeno.

Vipin Jain
fonte
1

Meu entendimento é que ambos devem ser os mesmos desde que não lidemos com valores NULL.

O mesmo motivo pelo qual a consulta não retorna o valor para = NULL vs é NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

Quanto ao argumento booleano vs comparador, para gerar um valor booleano, ambos os valores precisam ser comparados e é assim que qualquer condição if funciona. Portanto, não entendo como IN e EXISTS se comportam de maneira diferente.

Ranjeeth
fonte
0

Se uma subconsulta retornar mais de um valor, pode ser necessário executar a consulta externa - se os valores na coluna especificada na condição corresponderem a qualquer valor no conjunto de resultados da subconsulta. Para executar esta tarefa, você precisa usar oin palavra chave

Você pode usar uma subconsulta para verificar se existe um conjunto de registros. Para isso, você precisa usar a existscláusula com uma subconsulta. A existspalavra-chave sempre retorna valor verdadeiro ou falso.

djohn
fonte
0

Acredito que isso tenha uma resposta direta. Por que você não verifica isso das pessoas que desenvolveram essa função em seus sistemas?

Se você é desenvolvedor de MS SQL, aqui está a resposta diretamente da Microsoft.

IN:

Determina se um valor especificado corresponde a qualquer valor em uma subconsulta ou lista.

EXISTS:

Especifica uma subconsulta para testar a existência de linhas.

Erro fatal
fonte
0

Descobri que o uso da palavra-chave EXISTS geralmente é muito lento (isso é verdade no Microsoft Access). Em vez disso, eu uso o operador join desta maneira: devo-usar-a-palavra-chave-existe-no-sql

Axel Der
fonte
-1

EXISTE É mais rápido em desempenho que em. Se a maioria dos critérios de filtro estiver na subconsulta, é melhor usar IN e Se a maioria dos critérios de filtro estiver na consulta principal, é melhor usar EXISTS.

Deva
fonte
Essa alegação não é realmente apoiada por nenhuma evidência, é?
Lukas Eder
-2

Se você estiver usando o operador IN, o mecanismo SQL verificará todos os registros buscados na consulta interna. Por outro lado, se estivermos usando EXISTS, o mecanismo SQL interromperá o processo de verificação assim que encontrar uma correspondência.

Gagandeep Singh
fonte
@ziggy explicar? Isso é basicamente o que a resposta aceita também diz. Em DEVE verificar cada registro, existe um pode parar assim que encontrar apenas um.
Ben Thurley
Não, não está correto. INe EXISTSpodem ser equivalentes e transformados um no outro.
Lukas Eder