Aggiornare:
Questi articoli nel mio blog descrivono le differenze tra i metodi in modo più dettagliato:
Esistono tre modi per eseguire tale query:
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 a NULL
.
Questo può essere fonte di 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
valore produce il NULL
risultato che rende anche l'intero risultato NULL
.
Non possiamo mai dire con certezza che common_id
non è uguale a niente da 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
ritornerà 3
, NOT IN
non restituirà nulla (dal momento che valuterà sempre a FALSE
o NULL
).
In MySQL
, nel caso di colonne non annullabili, LEFT JOIN / IS NULL
e NOT IN
sono un po '(diversi percento) più efficienti di NOT EXISTS
. Se la colonna è nullable, NOT EXISTS
è la più efficiente (di nuovo, non molto).
In Oracle
, tutte e tre le query producono gli stessi piani (an ANTI JOIN
).
In SQL Server
, NOT IN
/ NOT EXISTS
sono più efficienti, dal momento che 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
, sinusoidali sono ottimizzati per un Anti Join
, mentre NOT IN
usi hashed subplan
(o anche un semplice subplan
se la subquery è troppo grande per l'hash)