Differenza tra EXISTS e IN in SQL?


443

Qual è la differenza tra la clausola EXISTSe INin SQL?

Quando dovremmo usare EXISTSe quando dovremmo usare IN?

Risposte:


224

La existsparola chiave può essere utilizzata in questo modo, ma in realtà è intesa come un modo per evitare il conteggio:

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

Questo è molto utile laddove hai ifdichiarazioni condizionali, poiché existspuò essere molto più veloce di count.

Il inè utilizzato al meglio in cui si dispone di un elenco statico di passare:

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

Quando hai una tabella in inun'istruzione ha più senso usare un join, ma soprattutto non dovrebbe importare. Query Optimizer dovrebbe restituire lo stesso piano in entrambi i modi. In alcune implementazioni (per lo più precedenti, come Microsoft SQL Server 2000) le inquery riceveranno sempre un piano di join nidificato , mentre le joinquery utilizzeranno nidificato, unisci o hash come appropriato. Le implementazioni più moderne sono più intelligenti e possono adattare il piano anche quando inviene utilizzato.


2
Potresti approfondire "Quando hai una tabella in un'istruzione in ha più senso usare un join, ma non ha molta importanza. Query Optimizer restituirà lo stesso piano in entrambi i modi". Non la parte di Query Optimizer, la parte in cui è possibile utilizzare a JOINin sostituzione IN.
farthVader,

select * from [table] where [field] in (select [field] from [table2])restituisce gli stessi risultati (e piano di query) di select * from [table] join [table2] on [table2].[field] = [table].[field].

@Sander no: la prima query restituisce tutte le colonne table, mentre la seconda restituisce tutto da tablee table2. In alcuni database SQL (per lo più vecchi) la inquery verrà implementata come join nidificato, mentre la joinquery può essere nidificata, unita, hash, ecc., Qualunque sia la più rapida.
Keith il

2
Va bene, avrei dovuto specificare le colonne nella clausola select, ma dovresti aggiornare la tua risposta perché indica chiaramente che le query "restituiranno lo stesso piano in entrambi i modi".

existspuò essere utilizzato all'interno di un'istruzione case, quindi possono essere utili in questo modo anche ad es.select case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie

125

EXISTSti dirà se una query ha restituito risultati. per esempio:

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

IN viene utilizzato per confrontare un valore con diversi e può utilizzare valori letterali, come questo:

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

Puoi anche utilizzare i risultati della query con la INclausola, in questo modo:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)

3
L'ultima query è pericolosa perché potrebbe non riuscire nel caso in cui la sottoquery non restituisca alcun risultato. La clausola 'in' richiede almeno 1 argomento ...
user2054927

40
@ user2054927 L'ultima query non restituirà correttamente nessuna riga se la subquery non restituisce alcuna riga - nulla di pericoloso al riguardo!
Tony Andrews,

La migliore risposta
Aminadav Glickshtein,

81

Basato sull'ottimizzatore delle regole :

  • EXISTSè molto più veloce di INquando i risultati della sottoquery sono molto grandi.
  • INè più veloce di EXISTSquando i risultati della query secondaria sono molto piccoli.

Basato sull'ottimizzatore dei costi :

  • Non c'è differenza.

21
Prova del tuo argomento? Non credo che IN sarebbe più veloce di EXISTS di sempre!
Nawaz,

22
@Nawaz Che ne dici della prova per cui IN è sempre più lento di EXISTS?
ceving il

2
Query Optimizer implementato male? Mi sembra che qualcosa del genere (sebbene non esattamente questa situazione) accada in alcuni RDBM ...
Haroldo_OK

1
EXISTS restituisce valori puramente booleani, che è sempre più veloce di dover confrontare stringhe o valori maggiori di un tipo BIT / Booleano. IN può essere o meno un confronto booleano. Poiché la programmazione preferisce l'utilizzo di EXPLICIT per la stabilità (parte di ACID), EXISTS è generalmente preferito.
clifton_h,

2
Perché questo è stato votato così tante volte? Non c'è assolutamente alcun motivo per cui questa affermazione basata sul presupposto dovrebbe essere generalmente vera.
Lukas Eder,

40

Suppongo che tu sappia cosa fanno, e quindi vengano usati in modo diverso, quindi comprenderò la tua domanda come: quando sarebbe una buona idea riscrivere l'SQL da usare IN invece di EXISTS, o viceversa.

È un presupposto giusto?


Modifica : il motivo per cui sto chiedendo è che in molti casi è possibile riscrivere un SQL basato su IN per utilizzare un EXISTS, e viceversa, e per alcuni motori di database, Query Optimizer tratterà i due in modo diverso.

Per esempio:

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

può essere riscritto in:

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

o con un join:

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

Quindi la mia domanda è ancora valida: il poster originale si chiede cosa faccia IN e EXISTS, e quindi come usarlo, o chiede se riscrivere un SQL usando IN per usare EXISTS, o viceversa, sarà una buona idea?


12
Non conosco il PO, ma vorrei la risposta a questa domanda! Quando dovrei usare EXISTS invece di IN con una sottoquery che restituisce ID?
Roy Tinker,

8
nel JOIN, avrai bisogno di unDISTINCT
Jaider

4
grande dimostrazione, ma praticamente lasciamo la domanda senza risposta
Junchen Liu

28
  1. EXISTSè molto più veloce di INquando i risultati della subquery sono molto grandi.
    INè più veloce di EXISTSquando i risultati della subquery sono molto piccoli.

    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. Query 1

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

    Query 2

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

    Se nel t1tuo ID ha valore nullo, la query 1 li troverà, ma la query 2 non può trovare i parametri null.

    Voglio dire, INnon è possibile confrontare nulla con null, quindi non ha alcun risultato per null, ma EXISTSpuò confrontare tutto con null.


Questa risposta è una sinossi ragionevole del sentimento di Tom Kite ( asktom.oracle.com/pls/asktom/… )
Jeromy French

Penso che questa risposta si basi sull'intuizione, che è abbastanza giusta. Ma non può essere universalmente vero. Ad esempio, quasi certamente non è vero per Ingres , che analizzerebbe entrambe le query SQL equivalenti come la stessa query QUEL, che manca della "ricchezza" di SQL quando si tratta di scrivere la stessa cosa in più modi.
Onedayquando il

Queste 2 query sono logicamente equivalenti se e solo se t2.id è definito come "NOT NULL". Per garantire l'equivalenza senza dipendenza nella definizione della tabella, la seconda query dovrebbe essere "SELEZIONA t1. * DA t1 DOVE t1.id non è presente (SELEZIONA t2.id DA t2 dove t2.id non è nullo )"
David דודו Markovitz

16

Se si utilizza l' INoperatore, il motore SQL eseguirà la scansione di tutti i record recuperati dalla query interna. D'altra parte, se lo stiamo utilizzando EXISTS, il motore SQL interromperà il processo di scansione non appena avrà trovato una corrispondenza.


10

IN supporta solo le relazioni di uguaglianza (o disuguaglianza quando precedute da NOT ).
È sinonimo di = any / = some , ad es

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

EXISTS supporta tipi diversi di relazioni, che non possono essere espresse utilizzando IN , ad es.

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 su una nota diversa -

Le presunte differenze tecniche e prestazionali tra EXISTS e IN possono derivare da implementazioni / limitazioni / bug specifici del fornitore, ma molte volte non sono altro che miti creati a causa della mancanza di comprensione dei database interni.

La definizione delle tabelle, l'accuratezza delle statistiche, la configurazione del database e la versione dell'ottimizzatore hanno tutti un impatto sul piano di esecuzione e quindi sulle metriche delle prestazioni.


Valorizza il tuo commento sulle prestazioni: senza concentrarci su un DBMS specifico, dovremmo presumere che spetti all'ottimizzatore capire cosa funziona meglio.
Manngo,

9

La Existsparola chiave valuta vero o falso, ma la INparola chiave confronta tutti i valori nella corrispondente colonna secondaria. Un altro Select 1può essere utilizzato con il Existscomando. Esempio:

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

Ma INè meno efficiente e Existspiù veloce.


5

Penso,

  • EXISTSè quando è necessario abbinare i risultati della query con un'altra sottoquery. I risultati della query n. 1 devono essere recuperati in corrispondenza dei risultati di SubQuery. Tipo di join ... Ad esempio, selezionare la tabella clienti n. 1 che ha effettuato anche ordini tabella n. 2

  • IN serve per recuperare se il valore di una colonna specifica si trova in INun elenco (1,2,3,4,5) Ad esempio, selezionare i clienti che si trovano nei seguenti codici zip, ovvero i valori zip_code si trovano nell'elenco (....).

Quando usarlo l'uno sull'altro ... quando ritieni che legga in modo appropriato (comunica meglio l'intento).


4

La differenza sta qui:

select * 
from abcTable
where exists (select null)

La query sopra restituirà tutti i record mentre quella sotto restituirà vuota.

select *
from abcTable
where abcTable_ID in (select null)

Provalo e osserva l'output.


1
Hmmm ... Errore: [SQL0104] Token) non valido. In entrambi i casi. Stai assumendo un RDBMS particolare?
jmarkmurphy,

3

Secondo la mia conoscenza, quando una sottoquery restituisce un NULLvalore, allora l'intera istruzione diventa NULL. In questi casi stiamo usando la EXITSparola chiave. Se vogliamo confrontare determinati valori nelle sottoquery, stiamo usando la INparola chiave.


3

Quale è più veloce dipende dal numero di query recuperate dalla query interna:

  • Quando la tua query interna recupera migliaia di righe, allora EXIST sarebbe la scelta migliore
  • Quando la tua query interna recupera poche righe, IN sarà più veloce

EXIST valuta su vero o falso ma IN confronta valori multipli. Quando non sai che il record esiste o meno, dovresti scegliere ESISTERE


3

Il motivo è che l'operatore EXISTS lavora in base al principio "almeno trovato". Restituisce vero e interrompe la scansione della tabella una volta trovata almeno una riga corrispondente.

D'altra parte, quando l'operatore IN viene combinato con una sottoquery, MySQL deve prima elaborare la sottoquery e quindi utilizzare il risultato della sottoquery per elaborare l'intera query.

La regola generale è che se la subquery contiene un grande volume di dati, l'operatore EXISTS fornisce prestazioni migliori.

Tuttavia, la query che utilizza l'operatore IN sarà più veloce se il set di risultati restituito dalla sottoquery è molto piccolo.


1

La mia comprensione è che entrambi dovrebbero essere gli stessi purché non si tratti di valori NULL.

Lo stesso motivo per cui la query non restituisce il valore per = NULL vs è NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

Per quanto riguarda l'argomento booleano vs comparatore, per generare un valore booleano è necessario confrontare entrambi i valori ed è così che funziona qualsiasi condizione if. Quindi non riesco a capire come IN ed EXISTS si comportino diversamente.



0

Se una sottoquery restituisce più di un valore, potrebbe essere necessario eseguire la query esterna, se i valori all'interno della colonna specificata nella condizione corrispondono a qualsiasi valore nel set di risultati della sottoquery. Per eseguire questa attività, è necessario utilizzare la inparola chiave.

È possibile utilizzare una sottoquery per verificare l'esistenza di un set di record. Per questo, è necessario utilizzare la existsclausola con una sottoquery. La existsparola chiave restituisce sempre il valore vero o falso.


0

Credo che questa abbia una risposta semplice. Perché non lo controlli dalle persone che hanno sviluppato quella funzione nei loro sistemi?

Se sei uno sviluppatore MS SQL, ecco la risposta direttamente da Microsoft.

IN:

Determina se un valore specificato corrisponde a qualsiasi valore in una sottoquery o in un elenco.

EXISTS:

Specifica una sottoquery per verificare l'esistenza di righe.



-1

EXISTS ha prestazioni più veloci di IN. Se la maggior parte dei criteri di filtro si trova nella sottoquery, è meglio usare IN e Se la maggior parte dei criteri di filtro è nella query principale, allora è meglio usare EXISTS.


Questa affermazione non è davvero supportata da alcuna prova, vero?
Lukas Eder,

-2

Se si utilizza l'operatore IN, il motore SQL eseguirà la scansione di tutti i record recuperati dalla query interna. D'altra parte se stiamo usando EXISTS, il motore SQL interromperà il processo di scansione non appena avrà trovato una corrispondenza.


@ziggy spiega? Questo è praticamente ciò che dice anche la risposta accettata. In DEVE controllare ogni singolo record, esiste può fermarsi non appena ne trova uno solo.
Ben Thurley,

No, non corretto. INe EXISTSpuò essere equivalente e trasformarsi l'uno nell'altro.
Lukas Eder,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.