Existe alguma diferença material entre as consultas unidas pelas cláusulas WHERE e as consultas usando um JOIN real?

32

No Learn SQL the Hard Way (exercício seis) , o autor apresenta a seguinte consulta:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

e depois continua dizendo que:

Na verdade, existem outras maneiras de fazer com que esses tipos de consultas funcionem chamados "junções". Estou evitando esses conceitos por enquanto, porque eles são incrivelmente confusos. Apenas se atenha a essa maneira de ingressar nas tabelas por enquanto e ignore as pessoas que tentam dizer a você que isso é de alguma forma mais lento ou "classe baixa".

Isso é verdade? Por que ou por que não?

Robert Harvey
fonte
3
Eu não acho que exista, mas você pode tentar fazer um EXPLAIN para ver se há alguma diferença na execução da consulta.
GrandmasterB
6
Eu gostaria de apontar os sinais conflitantes de um trabalho com "The Hard Way" no título pulando um conceito "porque eles são incrivelmente confusos". Mas talvez apenas meu conceito de como "o caminho difícil" deva estar errado. Mas, novamente, talvez não.
Mindwin
7
JOIN transporta muito bem a intenção (unir tabelas), isso deixa a parte WHERE dos filtros reais e facilita um pouco a leitura. (além de outras implicações maaany)
Th 00 ma s
2
Você está aprendendo SQL da maneira mais difícil se o autor não puder se incomodar em criar uniões simples! Como o ThomasS diz, usando JOINs, as intenções são esclarecidas e as cláusulas WHERE se tornam muito mais simples. Também o uso de JOINs ilustra melhor a teoria dos conjuntos que sustenta o SQL.
precisa saber é o seguinte
1
Não tenho certeza de como me sinto sobre algo que pretende ensinar algo a você enquanto diz "Mas, ei, vamos pular esse conceito fundamental porque são bananas de craaazzzyyyy". Acho que acabaria procurando uma fonte diferente para aprender. Em algum momento, você precisará fazer junções externas e cruzadas e deve saber como fazê-las.
Maurice Reeves

Respostas:

23

Com a abordagem do autor, o ensino de OUTER JOINs será muito mais difícil. A cláusula ON de INNER JOIN nunca foi alucinante para mim, como muitas outras coisas. Talvez seja porque nunca aprendi da maneira antiga. Eu gostaria de pensar que há uma razão pela qual nos livramos dela e não era para ser convencido e chamar esse método de classe baixa.

É verdade no cenário muito restrito que o autor criou:

  • Esse nível básico de SQL que usar ON é complexo
  • Apenas considerando JOIN / INNER JOIN e não JOIN EXTERIORES
  • O codificador isolado que não precisa ler o código de outras pessoas nem tem experiência com o uso do ON lendo / usando seu código.
  • Não requer consultas complexas com muitas tabelas: if, but's e or's.

Como parte de uma progressão de ensino, acho que é mais fácil decompô-la e ter uma progressão natural:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Os conceitos de união e filtragem de tabelas não são realmente os mesmos. Aprender a sintaxe correta agora terá mais carry-over quando você aprender as junções externas a menos que o autor tem a intenção de ensinar ultrapassadas / coisas obsoletas, como: *= or =*.

JeffO
fonte
5
A razão pela qual a instrução JOIN foi adicionada foi porque não havia um padrão para expressar associações externas, portanto cada fornecedor de banco de dados tinha sua própria sintaxe "especial" (incompatível). O IIRC Oracle tinha *=ou =*indicava associações externas esquerda ou direita, outro que eu usei apenas suportou associações externas esquerdas usando um |=operador.
TMN
1
@TMN IIRC Oracle usou +=ou talvez tenha sido =+. Eu acredito que *=era Transact-SQL (Sybase e mais tarde MS-SQL). Ainda assim, bom argumento.
David
1
Onde começa a ficar complicado (IMHO) é quando você tem uma mistura de junções internas e externas. Nesse tipo de situação, confesso que às vezes recorro à técnica de "classe baixa" de executar minhas junções na WHEREcláusula. (Eu já ouvi essa referida como uma teta juntar-se , mas eu não tenho certeza se isso é correto.)
David
Operadores IIRC como "maior que" ou "igual a" eram chamados de "operadores teta", mas uma pesquisa no google leva a alguma operação no cálculo.
Walter Mitty 31/01
12

O fato de ser mais lento depende do Query Optimizer e de como ele otimiza a consulta (o que você escreve não é realmente o que é executado). No entanto, o grande problema dessa citação é que ela ignora completamente o fato de que existem diferentes tipos de junções que operam de maneira completamente diferente. Por exemplo, o que está sendo dito é (teoricamente) verdadeiro para inner joins, mas não é válido para outer joins( left joinse right joins).

Locke
fonte
9
+1 Para outros tipos de junções. A maioria das minhas junções são INNER JOINou LEFT OUTER JOIN. Eles não são "insanamente confusos". O SQL pode ficar incrivelmente confuso, mas este não é um exemplo disso.
mgw854
off topic, mas deve a declaração ser diferentes tipos de juntar-se s ou tipos de juntar-se ?
precisa saber é o seguinte
9

O autor apresenta um caso simples em que a sintaxe antiga ou nova pode ser usada. Não concordo com sua afirmação de que as junções são incrivelmente confusas, porque a junção de tabelas é um conceito fundamental de consulta SQL. Portanto, talvez o autor deva ter passado algum tempo explicando como o JOINS funciona antes de proferir uma declaração opinativa, bem como fazer um exemplo de consulta de tabela múltipla.

Deve-se usar a sintaxe mais recente. O principal argumento para isso é que sua consulta terá:

  • Selecionar Critérios
  • Critérios de adesão
  • Critérios de filtro

Usando o estilo antigo, os critérios de junção e filtro são combinados, o que, em casos mais complexos, pode causar confusão.

Além disso, pode-se obter um produto cartesiano esquecendo um critério de junção na cláusula de filtro:

 person_pet.person_id = person.id

usando a sintaxe mais antiga.

O uso da sintaxe mais recente também especifica como a junção deve ocorrer, o que é importante se você deseja um INTERNO, ESQUERDO EXTERIOR etc., para que seja mais explícito em relação à sintaxe JOIN, que IMHO aumenta a legibilidade para aqueles que não estão familiarizados com as tabelas de junção.

Jon Raynor
fonte
5

Não deveria haver, o analisador de consultas deve gerar uma representação interna equivalente para consultas equivalentes, independentemente de como elas sejam gravadas. O autor está apenas usando a sintaxe pré-SQL-92, e é por isso que ele menciona que pode ser vista como "antiquada" ou "classe baixa". Internamente, o analisador e o otimizador devem gerar o mesmo plano de consulta.

TMN
fonte
5

Eu aprendi SQL dessa maneira, incluindo o *= sintaxe para junções externas. Para mim, foi muito intuitivo, pois todas as relações tiveram igual precedência e fizeram um trabalho melhor ao configurar consultas como uma série de perguntas: O que você quer? De onde você os quer? Quais você quer?

Ao fazer a joinsintaxe, interrompe o processo de pensamento em relação às relações com mais força. E, pessoalmente, acho o código muito menos legível com as tabelas e relações entrelaçadas.

Pelo menos no MSSQL, não há diferença significativa no desempenho das consultas, supondo que você use a mesma ordem de junção. Dito isto, há um problema claro e enorme com o aprendizado (e o uso) de SQL dessa maneira. Se você esquecer uma de suas relações, obterá produtos cruzados inesperados. Que em um banco de dados de qualquer tamanho não trivial é proibitivamente caro (e perigoso para não-selecionados!). É muito mais difícil esquecer uma relação ao usar a joinsintaxe de estilo.

Telastyn
fonte
7
Como um banco de dados relacional , as relações são muito importantes para uma consulta. Pessoalmente, acho muito mais difícil entender uma consulta que combina filtros verdadeiros (foo.x = 5) com relacionamentos (foo.x = bar.x). O mecanismo pode otimizar isso facilmente em uma junção, mas um ser humano precisa essencialmente raciocinar linha por linha, em oposição a conjuntos e subconjuntos.
Aaronaught 16/01
4

Há dois aspectos diferentes a serem considerados: Desempenho e Manutenção / Legibilidade .

Manutenção / Legibilidade

Eu escolhi uma consulta diferente, pois acho que é um exemplo melhor / pior do que a consulta original que você postou.

O que parece melhor para você e é mais legível?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

Ou...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Para mim, pessoalmente, o primeiro é bastante legível. Você vê que estamos juntando tabelas comINNER JOIN , o que significa que estamos puxando as linhas correspondentes na cláusula de junção subseqüente (por exemplo, "junte Employee com EmployeeDepartmentHistory em BusinessEntityID e inclua essas linhas").

O último, a vírgula não significa nada para mim. Isso me faz pensar no que você está fazendo com todos essesWHERE predicados de cláusulas.

O primeiro lê mais como meu cérebro pensa. Eu olho para o SQL o dia inteiro todos os dias e as vírgulas para junções. O que me leva ao meu próximo ponto ...

Na verdade, existem outras maneiras de fazer com que esses tipos de consultas funcionem chamados "junções"

Todos são junções. Até as vírgulas são uma junção. O fato de o autor não os chamar de fato é a queda deles ... não é óbvio. Deveria ser óbvio. Você está juntando dados relacionais, independentemente de especificar JOINou, .

atuação

Definitivamente, isso depende do RDBMS. Só posso falar em nome do Microsoft SQL Server. Em termos de desempenho, estes são equivalentes. Como você sabe? Capture os planos pós-execução e veja o que exatamente o SQL Server está fazendo por cada uma destas instruções:

insira a descrição da imagem aqui

Na imagem acima, destaquei que estou usando as duas consultas acima, diferindo apenas nos caracteres explícitos da junção ( JOINvs, ). O SQL Server faz exatamente a mesma coisa.

Sumário

Não use vírgulas. Use JOINinstruções explícitas .

Thomas Stringer
fonte
Aprendi INNER JOINs muito antes de perceber que a variante com as cláusulas WHERE é equivalente e os dois exemplos me parecem muito legíveis. Aquele com as WHEREs e as vírgulas pode ser ainda mais legível. O ponto em que ele cai, eu acho, é em grandes consultas complexas, não essas relativamente simples.
Robert Harvey
A questão é que pensar que a variação de vírgula não é uma junção relacional não está correto.
Thomas Stringer
Acho que você está interpretando incorretamente as vírgulas como junções. As vírgulas apenas separam as tabelas; são as condições WHERE que criam as junções, não as vírgulas.
Robert Harvey
1
Definitivamente, posso dizer que não há nenhuma associação entre as cláusulas de predicado. Acho que você está interpretando incorretamente as construções da sua consulta relacional. Você já tentou juntar sua vírgula sem as cláusulas WHERE? Ainda funciona. É uma junção cartesiana. O que você acha que está ganhando usando vírgulas? Por favor, não diga que você está tentando salvar personagens.
Thomas Stringer
1
Eu diria que o primeiro é melhor porque suas intenções são mais claras. Há muito menos ambiguidade.
precisa saber é o seguinte
4

Não, não é verdade. O autor está configurando seus leitores para confusão e incentivando a programação de cultos de carga que evita uma diferença estrutural muito poderosa entre a sintaxe padrão e essa variante mais antiga que ele prefere. Especificamente, uma cláusula WHERE desorganizada torna mais difícil descobrir o que torna sua consulta especial.

Seu exemplo leva um leitor a gerar um mapa mental de seu significado, que tem uma enorme quantidade de confusão.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

Aproximadamente, o acima é:

Obtenha o ID do animal de estimação, NAME, AGE e DEAD para todos os animais de estimação, person_pet e pessoas em que o ID do animal coincide com o pet_id de um person_pet, e o person_id desse registro coincide com o person_id de uma pessoa cujo FIRST_NAME é "Zed"

Com um mapa mental como esse, o leitor (que está escrevendo o SQL manualmente por algum motivo) pode cometer um erro muito fácil, possivelmente omitindo uma ou mais tabelas. E um leitor de código escrito dessa maneira terá que trabalhar mais para descobrir exatamente o que o autor do SQL está tentando fazer. ("Mais difícil" está no nível de leitura de SQL com ou sem destaque de sintaxe, mas ainda é uma diferença maior que zero.)

Há uma razão pela qual o JOIN é comum, e é o velho clássico "separação de preocupações". Especificamente, para uma consulta SQL, há um bom motivo para separar como os dados são estruturados e como os dados são filtrados.

Se a consulta for escrita mais limpa, como

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

Então o leitor tem uma distinção mais clara entre os componentes do que está sendo solicitado. O filtro distintivo dessa consulta é separado de como seus componentes se relacionam entre si, e os componentes necessários de cada relação estão diretamente próximos ao local em que são necessários.


Obviamente, qualquer sistema de banco de dados moderno não deve ver uma diferença significativa entre os dois estilos. Mas se o desempenho do banco de dados fosse a única consideração, a consulta SQL também não teria espaço em branco ou capitalização.

DougM
fonte
2
Desde que ouvi esse refrão várias vezes, deixe-me bancar o advogado do diabo. Learn X the Hard Way é sobre ter profundidade técnica; qualquer pessoa com um bom entendimento de SQL realmente deve saber que as duas abordagens são equivalentes, em termos da saída que produzem.
Robert Harvey
1
Percebo isso, mas o autor não está simplesmente afirmando que são declarações equivalentes a um servidor SQL decente; eles afirmam que o uso de JOIN é "confuso", que é um caminho pelo qual o código sujo aguarda. ("Não, não use LINQ, basta escrever sua instrução FOR à mão." "O compilador não se importa com o que eu chamo de método, portanto não há razão para não chamá-lo de FN1")
DougM
3

Guy está cometendo um erro clássico. Ele está tentando ensinar um conceito abstrato com uma implementação específica. Assim que você faz isso, você entra nesse tipo de bagunça.

Deveria ter ensinado conceitos básicos de banco de dados primeiro, depois mostrado o SQL como uma maneira de descrevê-los.

Junções esquerda e direita, pode-se argumentar que não importam muito. Junção externa, bem, você pode usar a antiga *=e a =*sintaxe.

Agora você pode argumentar que a sintaxe é mais simples, mas apenas para consultas simples. Assim que você começar a tentar fazer uma consulta complexa com esta versão, poderá entrar em uma confusão horrível. A sintaxe "nova" não foi introduzida para que você pudesse fazer consultas complexas, mas para fazer consultas complexas de maneira legível e, portanto, sustentável.

Tony Hopkinson
fonte
3
"Aprenda X da maneira mais difícil" é uma abordagem de aprendizado diferente. Você escreve o código e o entende mais tarde.
Robert Harvey
7
@RobertHarvey Essa não é uma abordagem de aprendizado diferente, é a padrão. Mais tarde, só acontece se você ainda estiver no lugar quando as rodas se soltarem. lidou com muitas pessoas escrevendo SQL que pensam que uma tabela é uma matriz retangular de células para ter confiança nesse método.
Tony Hopkinson
2

O exemplo é equivalente à reformulação simples com JOINs internos. A diferença está apenas nas possibilidades adicionais que a sintaxe JOIN permite. Por exemplo, você pode especificar a ordem em que as colunas das duas tabelas envolvidas são processadas; veja, por exemplo, https://stackoverflow.com/a/1018825/259310 .

A sabedoria recebida é, em caso de dúvida, escrever suas consultas da maneira que as torna mais legíveis. Mas se as formulações JOIN ou WHERE são mais fáceis de ler parece ser uma questão de preferência pessoal, e é por isso que ambas as formas são tão difundidas.

Kilian Foth
fonte
Boa resposta, embora o uso WHEREou a cláusula na JOINdeclaração possa realmente afetar o desempenho, dependendo do Query Optimizer. Eu já vi isso acontecer mais de uma vez.
Locke
Minha experiência com o impacto no desempenho é a seguinte: junções implícitas permitirão ao otimizador de consultas mais opções para otimizar a consulta, o que pode parecer uma coisa boa, mas pode ser um problema. Especificamente, o otimizador de consulta pode ajustar a consulta de uma maneira no desenvolvimento e outra na produção. O otimizador pode ser enganado com o ajuste que reduz o desempenho. Minha recomendação é usar a sintaxe de junção explícita E confirmar que a junção está usando colunas que possuem índices de modo que o desempenho seja previsível.
Michael Potter
2

Quando aprendi SQL, os formulários INNER JOIN, LEFT JOIN etc. não existiam. Como outras respostas já declararam, diferentes dialetos do SQL implementaram junções externas usando sintaxe idiossincrática. Essa portabilidade danificada do código SQL. Para trazer o idioma de volta, foi necessário mudar e LEFT JOIN etc. foi o que eles decidiram.

É verdade que, para cada INNER JOIN, uma junção de vírgula equivalente com a condição de junção na cláusula WHERE pode ser gravada. Levei um tempo para migrar do gosto da forma antiga para a preferência da nova forma. Aparentemente, o autor de Learning SQL the Hard Way ainda acha que o caminho antigo é mais fácil.

Existem diferenças? Bem, sim, existem. A primeira é que um INNER JOIN com uma cláusula ON revela a intenção do autor mais claramente do que o estilo antigo. O fato de a cláusula ON ser de fato uma condição de junção e não outro tipo de restrição é mais óbvio. Isso torna o código que usa INNER JOIN mais fácil de aprender ao ler do que o estilo antigo. Isso é importante ao manter o código de outra pessoa.

A segunda diferença é que o novo estilo facilita marginalmente para o otimizador de consultas descobrir a estratégia vencedora. Este é um efeito muito pequeno, mas é real.

A terceira diferença é que, quando você aprende usando INNER JOIN (ou simplesmente JOIN), fica mais fácil aprender LEFT JOIN, etc.

Além disso, não há diferença material.

Walter Mitty
fonte
0

Depende se você pensa em termos de conjuntos e lógica formal .....

Se você não usar a palavra-chave "join", a progressão será mais simples da lógica formal para o SQL.

Mas se, como 99% das pessoas, você não gostava de lógica formal em seu curso de matemática, então a palavra-chave join é muito mais fácil de aprender. O SQL costumava ser apresentado na universidade apenas como outra maneira de escrever consultas lógicas formais ....

Ian
fonte