Aggiornamento:
Questi articoli nel mio blog descrivono le differenze tra i metodi in modo più dettagliato:
NOT IN
rispetto aNOT EXISTS
rispetto aLEFT JOIN / IS NULL
:SQL Server
NOT IN
rispetto aNOT EXISTS
rispetto aLEFT JOIN / IS NULL
:PostgreSQL
NOT IN
rispetto aNOT EXISTS
rispetto aLEFT JOIN / IS NULL
:Oracle
NOT IN
rispetto aNOT EXISTS
rispetto aLEFT JOIN / IS NULL
:MySQL
Esistono tre modi per eseguire una query del genere:
-
LEFT JOIN / IS NULL
:SELECT * FROM common LEFT JOIN table1 t1 ON t1.common_id = common.common_id WHERE t1.common_id IS NULL
-
NOT EXISTS
:SELECT * FROM common WHERE NOT EXISTS ( SELECT NULL FROM table1 t1 WHERE t1.common_id = common.common_id )
-
NOT IN
:SELECT * FROM common WHERE common_id NOT IN ( SELECT common_id FROM table1 t1 )
Quando table1.common_id
non è nullable, tutte queste query sono semanticamente uguali.
Quando è nullable, NOT IN
è diverso, poiché IN
(e, quindi, NOT IN
) restituisce NULL
quando un valore non corrisponde a nulla in un elenco contenente un NULL
.
Questo può creare confusione ma può diventare più ovvio se ricordiamo la sintassi alternativa per questo:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Il risultato di questa condizione è un prodotto booleano di tutti i confronti all'interno dell'elenco. Naturalmente, un singolo NULL
value restituisce il NULL
risultato che rende l'intero risultato NULL
anche.
Non possiamo mai dire con certezza che common_id
non è uguale a nulla di questo elenco, poiché almeno uno dei valori è NULL
.
Supponiamo di avere questi dati:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
e NOT EXISTS
restituirà 3
, NOT IN
restituirà nulla (dal momento che valuterà sempre come FALSE
o NULL
).
In MySQL
, nel caso in una colonna non nullable, LEFT JOIN / IS NULL
e NOT IN
sono un po' (diverse percentuali) più efficienti di NOT EXISTS
. Se la colonna è nullable, NOT EXISTS
è il più efficiente (di nuovo, non molto).
In Oracle
, tutte e tre le query producono gli stessi piani (un ANTI JOIN
).
In SQL Server
, NOT IN
/ NOT EXISTS
sono più efficienti, poiché LEFT JOIN / IS NULL
non può essere ottimizzato per un ANTI JOIN
dal suo ottimizzatore.
In PostgreSQL
, LEFT JOIN / IS NULL
e NOT EXISTS
sono più efficienti di NOT IN
, poiché sono ottimizzati per un Anti Join
, mentre NOT IN
utilizza hashed subplan
(o anche un semplice subplan
se la sottoquery è troppo grande per l'hash)