Usando a palavra-chave JOIN ou não

45

As seguintes consultas SQL são as mesmas:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

E certamente resultam nos mesmos planos de consulta em todos os DBMS que eu já tentei.

Mas, de vez em quando, leio ou ouço uma opinião de que uma é definitivamente melhor que a outra. Naturalmente, essas alegações nunca são substanciadas com uma explicação.

Onde trabalho, a segunda versão parece ser favorecida pela maioria dos outros desenvolvedores e, portanto, também costumo seguir esse estilo para minimizar a surpresa. Mas, no meu coração, estou realmente pensando no primeiro (já que foi assim que o aprendi originalmente).

Uma dessas formas é objetivamente melhor que a outra? Caso contrário, quais seriam os motivos para usar um sobre o outro?

SingleNegationElimination
fonte
1
Por que não criar um perfil e deixar o resto de nós saber o resultado? De um modo geral, o desempenho supera muito as preferências de estilo.
Demian Brecht
3
"resultam nos mesmos planos de consulta em todos os DBMS que eu já tentei" Se isso pudesse ter uma resposta em termos de desempenho, ela seria solicitada no stackoverflow.com. infelizmente, eles são a mesma consulta.
SingleNegationElimination
Ah .. Perdeu que :)
Demian Brecht
2
"Subjetivo" não significa "qual é a sua opinião". Eu editei este para o tipo de atender os critérios estabelecidos no FAQ .
Aaronaught
Eu também costumo seguir esse estilo para minimizar a surpresa. Acho que você acabou de responder sua própria pergunta. Surpresas são ruins.
Pieter B

Respostas:

60

Acho que a segunda forma é melhor. Talvez seja por isso que eu aprendi, admito, mas tenho uma razão concreta: a separação de preocupações. Colocar os campos que você está usando para ingressar nas tabelas na cláusula where pode levar a dificuldades para entender as consultas.

Por exemplo, faça a seguinte consulta:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

A consulta acima possui condições de junção de tabela e condições reais de lógica de negócios combinadas em um único espaço. Com uma consulta grande, isso pode ser muito difícil de entender.

No entanto, agora pegue este código:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

Nesse caso, qualquer coisa relacionada às tabelas ou como elas se relacionam é toda isolada na cláusula from, enquanto a lógica de negócios real da restrição de consulta está na cláusula where. Eu acho que isso é muito mais compreensível, principalmente para consultas maiores.

Dustin Wilhelmi
fonte
Essa é a única maneira sensata de fazê-lo, especialmente quando você passar de duas tabelas ou precisar de uma combinação de junções esquerda, direita e total.
aglassman
5
+1 Para "separação de interesses" junta dados reúnem, onde cláusulas ditar os subconjuntos de dados que você está interessado.
39

A sintaxe de junção substituiu a antiga sintaxe de vírgula em 1992. Atualmente, não há motivo para escrever código com a sintaxe de vírgula. Você não ganha nada e está sujeito a alguns problemas que simplesmente não possui com sintaxe explícita.

Em primeiro lugar, à medida que você obtém consultas mais complicadas, é muito fácil fazer uma junção cruzada acidental, perdendo uma condição where. Isso é algo que a sintaxe de junção explícita pode impedir que aconteça, pois você receberá um erro de sintaxe.

Se você pretende uma junção cruzada, a sintaxe de junção explícita deixará isso claro, enquanto na sintaxe implícita alguém que faz manutenção pode assumir que você esqueceu de adicionar a cláusula where.

Depois, há o problema de junções esquerda e direita que são problemáticas em pelo menos alguns dbs usando a sintaxe implícita. Eles foram descontinuados no SQL Server e, na verdade, não retornam resultados corretos de maneira confiável, mesmo nas versões mais antigas. Nenhuma consulta que precise de uma associação externa deve conter a sintaxe implícita no SQL Server.

Além disso, vi perguntas aqui e em outros sites em que resultados errados ocorreram quando as pessoas misturam as junções implícitas e explícitas (ao adicionar uma junção esquerda, por exemplo); portanto, é uma má idéia misturá-las.

Finalmente, muitas pessoas que usam junções implícitas realmente não entendem junções. Esse é um entendimento crítico que você deve ter para consultar efetivamente um banco de dados.

HLGEM
fonte
Obrigado pela explicação. Quando fui ensinado, foram mostradas as duas sintaxes, mas a diferença não foi explicada. Às vezes, eu conseguia produzir consultas com a falta de onde, que francamente aumentaria a quantidade de gravações, ao invés de se juntar explicitamente em primeiro lugar.
awiebe
8

Ha. Por acaso encontrei uma resposta possível para minha própria pergunta, enquanto olhava a documentação do PostgreSQL . Para resumir o que esta página explica, a consulta resultante ainda é a mesma, mas o número de planos que o otimizador deve considerar cresce exponencialmente com o número de junções.

Após cerca de seis dessas junções, o número é tão grande que o tempo para planejar a consulta pode ser perceptível e, depois das dez, o otimizador passa de uma pesquisa exaustiva de planos para uma pesquisa probabilística e pode não chegar ao plano ideal. .

Ao definir um parâmetro de tempo de execução, você pode instruir o planejador a tratar as junções internas e cruzadas mencionadas explicitamente de maneira diferente das junções implícitas, forçando-as ao topo do plano e não explorando outras opções.

De notar, o comportamento padrão é o mesmo em ambos os casos, e que obter planos alternativos requer conhecimento dos internos dos dbms e das peculiaridades das tabelas em questão para obter um resultado diferente

SingleNegationElimination
fonte
2
No entanto, você entendeu um pouco esses documentos. Em primeiro lugar, na verdade existem três limites. Um dispara o GEQO como você apontou; os outros dois (dos limites de recolhimento e de junção) acabam fazendo a plaina escolher os índices aplicáveis ​​em vez de reorganizar a ordem de junção. Em segundo lugar e com a mesma importância, as consultas são reescritas à medida que são analisadas. Isso resulta no primeiro exemplo de consulta sendo analisado exatamente na mesma árvore de árvore que a segunda - os limites informam à PG se ela deve tentar reordenar as junções ou não.
Denis de Bernardy
8

Bem, aqui está a visão da teoria dos conjuntos:

Quando você usa uma vírgula para separar dois (ou mais) nomes de tabela, o que você pretende é o produto cartesiano. Cada linha da tabela 'esquerda' será 'correspondida' (concatenada) com a da tabela direita.

Agora, se você escrever algo na cláusula where, é como colocar uma condição nessa 'concatenação' dizendo quais linhas 'concatenar' com quais linhas.

Na verdade, isso é "unir" as linhas :) e, portanto, a palavra-chave join que ajuda a fornecer uma sintaxe mais legível e é mais compreensível que você "de fato" queira ingressar em alguns valores comuns. Semelhante ao que @Dustin esclareceu acima.

Agora, todo DBMS é inteligente, ou seja, ele não calcula o produto cartesiano primeiro e depois filtra os dados (extremamente desperdiçador), mas o faz com base na estrutura da consulta. A única coisa em que consigo pensar é que, quando você pede para 'ingressar', é como tornar a atividade de junção explícita e provavelmente ajuda a executar o código mais rapidamente (em quanto? Você precisará criar um perfil e ver), mas no caso separado por vírgula, ele precisa de algum tempo para 'descobrir' a melhor estratégia. Posso estar errado, mas estou apenas tentando adivinhar como alguém poderia codificá-lo ...

Doutorado
fonte
5

Eu acho que geralmente é melhor usar instruções JOIN para esse caso.

Se, no futuro, surgir uma situação que exija a alteração de uma declaração de INNER JOIN para OUTTER JOIN, isso será muito mais fácil com a segunda declaração.

Britt Wescott
fonte
3

Qualquer RDBMS fará com que eles sejam a mesma coisa em termos de execução. Tudo se resume a se é mais legível e expressivo.

Use o JOIN para ficar claro o que é a correspondência de junção e o que é a seleção real, como em:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

O último caso deixa imediatamente claro qual é a condição de junção e qual é o critério de seleção.

Andy Lester
fonte
1

Eu só vi os dois resultados uma vez em um conjunto diferente de otimizações e, se a memória serve, estava no ms-sql2k em uma consulta realmente complicada. Nesse exemplo, a forma antiga usada com * = resultou em um desempenho cerca de 4x mais rápido. Ninguém, incluindo nossos técnicos da Microsoft, poderia explicar o porquê. Os caras da MS classificaram isso como um erro. Eu nunca mais vi isso.

Como a maioria dos RDBMS é inteligente o suficiente para não fazer cartesianos completos, a maior razão pela qual posso pensar em não usá-lo (além de ser depreciado) é que a maioria das pessoas com menos de 30 a 35 anos com quem trabalhei nunca viu o forma antiga antes e se perder terrivelmente quando a encontram.

Conta
fonte
É claro que a sintaxe de junção à esquerda nunca forneceu os resultados corretos de maneira confiável (consulte BOL para SQL Server 2000); portanto, mesmo que fosse mais rápido, eu a teria substituído.
HLGEM
Eu nunca encontrei isso, e pesquisar com o asterisco nunca termina bem, você tem um exemplo?
Bill
-1

O estilo antigo foi descontinuado, você não deve usá-lo.

Nem deveria haver uma discussão sobre qual é a melhor ou não. O novo código não deve usar a sintaxe antiga.

Pieter B
fonte
Acho que essa resposta realmente não adiciona nada sem dizer por que foi reprovada e não deve ser usada.
RemcoGerlich 23/04/2015
1
@RemcoGerlich porque foi preterido não está em discussão aqui. O que está em discussão aqui é se deve ser usada a sintaxe antiga ou nova. Se um é melhor que o outro ou não, é discutível: você não deve usar sintaxe antiga. A questão do porquê é outra discussão. (aquele que tem sido resolvido há 20 anos.)
Pieter B
-4

Uma razão para a sintaxe mais concisa é que ela é mais concisa, portanto, se você estiver confortável com ela, é mais fácil ler. Penso no caso detalhado como semelhante à escrita aritmética em COBOL, por exemplo, MULTIPLICAR A POR B DANDO C.

John Bickers
fonte
Votações negativas: Há algo factualmente incorreto nesta resposta ou elas foram apenas "discordam de você" votações negativas?
Adam Libuša 10/10