Aggiornamento:
Questi articoli nel mio blog descrivono le differenze tra i metodi in modo più dettagliato:
NOT INrispetto aNOT EXISTSrispetto aLEFT JOIN / IS NULL:SQL ServerNOT INrispetto aNOT EXISTSrispetto aLEFT JOIN / IS NULL:PostgreSQLNOT INrispetto aNOT EXISTSrispetto aLEFT JOIN / IS NULL:OracleNOT INrispetto aNOT EXISTSrispetto 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)