Atualizar:
Estes artigos no meu blog descrevem as diferenças entre os métodos em mais detalhes:
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 é nulo, NOT IN
é diferente, pois IN
(e, portanto, NOT IN
) retorna NULL
quando um valor não corresponde a nada em uma lista que contém a NULL
.
Isso pode ser confuso, mas pode se tornar mais óbvio se lembrarmos da sintaxe alternativa para isso:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
O resultado dessa condição é um produto booleano de todas as comparações na lista. Obviamente, um único NULL
valor produz o NULL
resultado que renderiza o resultado inteiro NULL
também.
Nunca podemos dizer definitivamente que isso common_id
não é igual a nada dessa lista, pois pelo menos um dos valores é NULL
.
Suponha que tenhamos esses dados:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
e NOT EXISTS
retornará 3
, NOT IN
não retornará nada (pois sempre será avaliado como um FALSE
ou NULL
).
In MySQL
, no caso de coluna não anulável, LEFT JOIN / IS NULL
e NOT IN
é um pouco (vários por cento) mais eficiente que NOT EXISTS
. Se a coluna for anulável, NOT EXISTS
é a 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 podem ser otimizados para um ANTI JOIN
por seu otimizador.
Em PostgreSQL
, LEFT JOIN / IS NULL
e NOT EXISTS
são mais eficientes do que NOT IN
, seno, eles são otimizados para an Anti Join
, while NOT IN
uses hashed subplan
(ou até simples, subplan
se a subconsulta for muito grande para o hash)