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_idnão é anulável, todas essas consultas são semanticamente iguais.
Quando é nulo, NOT INé diferente, pois IN(e, portanto, NOT IN) retorna NULLquando 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 NULLvalor produz o NULLresultado que renderiza o resultado inteiro NULLtambém.
Nunca podemos dizer definitivamente que isso common_idnã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 NULLe NOT EXISTSretornará 3, NOT INnão retornará nada (pois sempre será avaliado como um FALSEou NULL).
In MySQL, no caso de coluna não anulável, LEFT JOIN / IS NULLe 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 EXISTSsão mais eficientes, pois LEFT JOIN / IS NULLnão podem ser otimizados para um ANTI JOINpor seu otimizador.
Em PostgreSQL, LEFT JOIN / IS NULLe NOT EXISTSsão mais eficientes do que NOT IN, seno, eles são otimizados para an Anti Join, while NOT INuses hashed subplan(ou até simples, subplanse a subconsulta for muito grande para o hash)