Atualização:
Estes artigos no meu blog descrevem as diferenças entre os métodos com mais detalhes:
NOT IN
vs.NOT EXISTS
vs.LEFT JOIN / IS NULL
:SQL Server
NOT IN
vs.NOT EXISTS
vs.LEFT JOIN / IS NULL
:PostgreSQL
NOT IN
vs.NOT EXISTS
vs.LEFT JOIN / IS NULL
:Oracle
NOT IN
vs.NOT EXISTS
vs.LEFT JOIN / IS NULL
:MySQL
Existem três maneiras de fazer essa consulta:
-
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
não é anulável, todas essas consultas são semanticamente iguais. Quando é anulável,
NOT IN
é diferente, pois IN
(e, portanto, NOT IN
) return NULL
quando um valor não corresponde a nada em uma lista contendo um NULL
. Isso pode ser confuso, mas pode se tornar mais óbvio se lembrarmos a sintaxe alternativa para isso:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
O resultado desta condição é um produto booleano de todas as comparações dentro da lista. Claro, um único
NULL
valor produz o NULL
resultado que renderiza todo o resultado NULL
também. Nunca podemos dizer com certeza que
common_id
não é igual a nada desta lista, pois pelo menos um dos valores é NULL
. Suponha que temos estes dados:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
e NOT EXISTS
retornará 3
, NOT IN
retornará nada (já que sempre será avaliado como FALSE
ou NULL
). Em
MySQL
, no caso de coluna não anulável, LEFT JOIN / IS NULL
e NOT IN
são um pouco (vários por cento) mais eficientes que NOT EXISTS
. Se a coluna for anulável, NOT EXISTS
é o mais eficiente (novamente, não muito). Em
Oracle
, todas as três consultas geram os mesmos planos (um ANTI JOIN
). Em
SQL Server
, NOT IN
/ NOT EXISTS
são mais eficientes, pois LEFT JOIN / IS NULL
não pode ser otimizado para um ANTI JOIN
pelo seu otimizador. Em
PostgreSQL
, LEFT JOIN / IS NULL
e NOT EXISTS
são mais eficientes que NOT IN
, pois são otimizados para um Anti Join
, enquanto NOT IN
usa hashed subplan
(ou mesmo um simples subplan
se a subconsulta for muito grande para hash)