Fazer junções internas é uma técnica bastante comum em muitos bancos de dados. Eles são usados ​​para muitas coisas diferentes, como buscar linhas de várias tabelas ao mesmo tempo, bem como filtrar e classificar por valores de várias tabelas. No entanto, essa versatilidade tem suas desvantagens. Tome por exemplo a seguinte consulta:
SELECT * FROM Book
WHERE title LIKE "%foo%";
Por alguns motivos, a consulta deve ser estendida para filtrar também por autor:
SELECT Book.* FROM Book
INNER JOIN Author ON Book.author_id = Author.id
WHERE Book.title LIKE "%foo%"
AND Author.name = "Bar";
Observe algo? Apenas para adicionar UMA condição adicional, a consulta teve que ser alterada em TRÊS locais diferentes (adicionando a junção, adicionando a condição, qualificando todas as colunas). Além disso, você adicionou muita confusão ao namespace. Imagine a consulta ficando mais longa. Será óbvio que esta junção foi adicionada para filtrar por nome? Eu acho que não!
Uma maneira mais elegante de escrever isso é usando subconsultas:
SELECT * FROM Book
WHERE title LIKE "%foo%"
AND author_id IN
( SELECT id FROM Author WHERE name = "Bar" );
BÄM! Para adicionar UMA condição, a consulta foi alterada em UM lugar. Isso é muito mais limpo, um pouco mais curto e não adiciona lixo ao namespace. Mesmo que a consulta se torne maior, a subconsulta permanece dentro da cláusula WHERE.
Um motivo contra as subconsultas sempre foi que elas não têm o mesmo desempenho das junções. Isso não é mais verdade em sistemas de banco de dados modernos. Pegue o MySQL 5 e o Postgres 8. Ambos os sistemas reconhecem subconsultas que são independentes da consulta externa e as tratam exatamente como junções internas. Portanto, o desempenho é o mesmo!