Associações são para pessoas preguiçosas?

169

Recentemente, tive uma discussão com outro desenvolvedor que me afirmou que JOINs (SQL) são inúteis. Isso é tecnicamente verdade, mas ele acrescentou que o uso de junções é menos eficiente do que fazer várias solicitações e tabelas de links no código (C # ou Java).

Para ele, as junções são para pessoas preguiçosas que não se importam com desempenho. Isso é verdade? Devemos evitar o uso de junções?

Bastien Vandamme
fonte
114
Não. Os bancos de dados são otimizados para realizar junções, são extremamente rápidos, especialmente para grandes conjuntos de dados. Você não deseja que seu aplicativo carregue dezenas de milhares de linhas e as junte manualmente.
Halfdan
91
Linguagens de programação são para pessoas preguiçosas; eles são menos eficientes do que codificar as instruções da CPU manualmente. :)
Michael McGowan
76
Qual o nome do desenvolvedor? Quero garantir que nunca o contrate.
8111 Joe
39
@ Michael meh, programadores reais usar borboletas ...
Marc Gravell
14
Re seu "isso é verdade" - não, não é. Os bancos de dados funcionam via teoria dos conjuntos; junta-se em conjuntos de trabalhar muito bem e útil ...
Marc Gravell

Respostas:

188

Não, devemos evitar desenvolvedores que tenham opiniões incrivelmente erradas.

Em muitos casos, uma junção ao banco de dados é várias ordens de magnitude mais rápidas do que qualquer coisa feita através do cliente, porque evita viagens de ida e volta ao banco de dados, e o banco de dados pode usar índices para realizar a junção.

No topo da minha cabeça, nem consigo imaginar um cenário único em que uma junção usada corretamente seria mais lenta que a operação equivalente do lado do cliente.

Edit: Existem alguns casos raros em que o código do cliente personalizado pode fazer as coisas com mais eficiência do que uma junção direta ao banco de dados (consulte o comentário por meriton). Mas isso é muito a exceção.

Michael Borgwardt
fonte
1
E as junções de três vias? Não existem casos em que seria melhor fazê-los "no código"?
22711
56
A associação ao servidor de aplicativos pode ser mais eficiente se a associação ao banco de dados causar redundância severa no conjunto de resultados enviado pela rede. Considere as tabelas A e B, em que cada linha em A está associada a 20 linhas em B, B possui apenas 100 linhas e queremos buscar as primeiras 1000 linhas de A com linhas associadas de B. A associação ao banco de dados resultará em 20 * 1000 tuplas enviadas pela rede. Se a junção for feita no servidor de aplicativos (primeiro buscando a tabela B inteira na memória), apenas 100 + 1000 linhas serão enviadas pela rede.
meriton
7
No entanto, você está certo de que as junções no banco de dados são muito mais rápidas na maioria dos casos e, portanto, não apenas por uma questão de conveniência, mas também por necessidade.
meriton
13
Tive a sorte de falar com alguns dos desenvolvedores que trabalham no SQL Server na Microsoft. Isso o deixará atordoado ao ouvir as otimizações que eles fazem nas consultas. Quem pensa que é mais esperto do que isso precisa ser golpeado.
riwalk
2
@meriton Estou um pouco surpreso; Eu esperaria que a biblioteca do cliente otimizasse as junções cruzadas.
Phil Lello 5/05
83

Parece-me que seu colega faria bem com um banco de dados de documentos no-sql ou um armazenamento de valores-chave. Quais são eles mesmos ferramentas muito boas e adequadas para muitos problemas.

No entanto, um banco de dados relacional é altamente otimizado para trabalhar com conjuntos. Existem muitas, muitas maneiras de consultar os dados com base em junções que são muito mais eficientes do que muitas viagens de ida e volta. É daí que vem a versatilidade de um rdbms. Você também pode obter o mesmo em uma loja nosql, mas geralmente cria uma estrutura separada adequada para cada natureza diferente da consulta.

Em resumo: eu discordo. Em um RDBMS, as junções são fundamentais . Se você não os estiver usando, não o usará como um RDBMS.

Marc Gravell
fonte
46

Bem, ele está errado no caso geral.

Os bancos de dados podem otimizar usando uma variedade de métodos, ajudados por dicas do otimizador, índices de tabela, relacionamentos de chave estrangeira e possivelmente outras informações específicas do fornecedor do banco de dados.

ver
fonte
1
Devo admitir que, quando comecei a trabalhar com bancos de dados, tinha a mesma crença de que poderia superar o desempenho das junções. Mas não demorou muito para perceber como as junções incrivelmente rápidas são feitas pelo DB. Na verdade, eu diria que, nessa situação, é melhor discuti-lo com o funcionário de maneira aberta, em vez de descartá-lo como um idiota.
usar o seguinte comando
1
@LegendLength Eu diria que isso é verdade mesmo se não forem tão inteligentes. Não há necessidade de assumir a esperteza, porque eles cometem os mesmos erros que lembramos de cometer (de fato, para mim, isso pode significar que eles não são tão inteligentes ...) É mais simples: raramente ajuda a ser desprezível. Não há problema em estar errado, de vez em quando!
`` Ferramentas
24

Não, você não deveria.

Os bancos de dados são projetados especificamente para manipular conjuntos de dados (obviamente ...). Portanto, eles são incrivelmente eficientes para fazer isso. Ao fazer o que é essencialmente uma junção manual em seu próprio código, ele está tentando assumir o papel de algo especificamente projetado para o trabalho. As chances de seu código ser tão eficiente quanto o do banco de dados são muito remotas.

Como um aparte, sem junções, qual é o sentido de usar um banco de dados? ele também pode usar arquivos de texto.

richzilla
fonte
2
Mesmo sem junções? Mapeamento automático na memória, cache automático de consultas, muitas outras coisas automagicas que não acontecem na maioria dos sistemas de arquivos. Ah, eu mencionei transações finamente controláveis?
Piskvor saiu do prédio
19

Se "preguiçoso" é definido como pessoas que desejam escrever menos código, então eu concordo. Se "preguiçoso" é definido como pessoas que querem ter ferramentas fazem o que fazem, concordo. Então, se ele está apenas concordando com Larry Wall (sobre os atributos de bons programadores), então eu concordo com ele.

MJB
fonte
Eu adicionei a precisão do preguiçoso: para pessoas preguiçosas que não se importam com performances e preferem escrever menos código. Eu acho que as junções são para pessoas preguiçosas, mas, neste caso, as junções também são melhores do que várias solicitações.
Bastien Vandamme
3
@Dran Dane: Associações são para pessoas preguiçosas, sim. O fato de que eles provavelmente terão um bom desempenho é ortogonal.
Piskvor deixou o prédio
16

Ummm, joins é como os bancos de dados relacionais relacionam tabelas entre si. Não sei ao que ele está chegando.

Como fazer várias chamadas ao banco de dados pode ser mais eficiente do que uma chamada? Além disso, os mecanismos sql são otimizados para fazer esse tipo de coisa.

Talvez seu colega de trabalho tenha preguiça de aprender SQL.

Giovanni Galbo
fonte
12

Sim você deveria.

E você deve usar C ++ em vez de C # por causa do desempenho. C # é para pessoas preguiçosas.

Não não não. Você deve usar C em vez de C ++ por causa do desempenho. C ++ é para pessoas preguiçosas.

Não não não. Você deve usar assembly em vez de C por causa do desempenho. C é para pessoas preguiçosas.

Sim, estou brincando. você pode criar programas mais rápidos sem junções e pode criar programas usando menos memória sem junções. MAS, em muitos casos, o tempo de desenvolvimento é mais importante que o tempo e a memória da CPU. Desista de um pouco de desempenho e aproveite sua vida. Não perca seu tempo com pouco desempenho. E diga a ele: "Por que você não faz uma estrada reta do seu lugar para o seu escritório?"

RedPain
fonte
1
Analisei todas as suas respostas até agora e elas são muito engraçadas. Por favor, continuem chegando. Ou então, onde posso assinar o seu blog?
Gerry
11

"Isso é tecnicamente verdadeiro" - da mesma forma, um banco de dados SQL é inútil: qual é o sentido de usar um quando você pode obter o mesmo resultado usando vários arquivos CSV e correlacionando-os no código? Caramba, qualquer abstração é para pessoas preguiçosas, vamos voltar à programação em código de máquina diretamente no hardware! ;)

Além disso, sua afirmação é falsa em todos os casos, exceto nos mais complicados: os RDBMSs são fortemente otimizados para tornar os JOINs rápidos . Sistemas de gerenciamento de banco de dados relacional , certo?

Piskvor saiu do prédio
fonte
2
+1 A frase "... tecnicamente verdade" teria funcionado melhor se o OP tinha usado para palavra unnecessaryem vez uselessna frase anterior. Dizer que as junções são inúteis é evidentemente falso, sem necessidade de considerações técnicas. Em qualquer caso, o equívoco do colega do ponto de RDBMSs do OP e é sandly não é incomum: stackoverflow.com/q/5575682/47550
Paul Sasik
7

A última empresa em que trabalhei também não utilizava junções SQL. Em vez disso, eles moveram esse trabalho para a camada de aplicativo, projetada para ser dimensionada horizontalmente. A lógica para esse design é evitar o trabalho na camada de banco de dados. Geralmente é o banco de dados que se torna gargalo. É mais fácil replicar a camada de aplicativo do que o banco de dados. Pode haver outras razões. Mas este é o que eu me lembro agora.

Sim, eu concordo que as junções feitas na camada de aplicativo são ineficientes em comparação com as junções feitas pelo banco de dados. Mais comunicação em rede também.

Observe que não estou adotando uma postura rígida para evitar junções SQL.

Srikanth
fonte
Bem, isso soa como um argumento racional contra JOINs no seu caso específico. Lembro que a FB Engineering publicou algo semelhante em seu blog - a expansão também era sua principal prioridade. Infelizmente, apenas uma pequena% dos programadores nunca vai precisar fazer isso, mas muitos pensam que eles fazem "porque OMG Facebook também faz isso";)
Piskvor deixou a construção de
ok, em uma solução corporativa em que você tem tráfego suficiente para sobrecarregar o servidor de banco de dados, pode valer a pena considerar isso, mas é mais provável que seja o procedimento armazenado de relatório ou o backup agendado que pregue o desempenho. Bases de dados são bons em se junta, especialmente se houver indecies a ajuda
Jodrell
@Jodrell: Sim, eles são bons em junções; novamente, há casos de canto em que você precisa diminuir a elegância das junções para obter mais energia. Eu conheci uma dessas situações; tentamos todas as soluções possíveis e, de fato, uma solução sem junção foi a mais rápida nessa situação muito específica . E não, não havia mais nada em execução naquele servidor em particular; procedimentos armazenados não pode pará-lo se você não tem nenhuma;)
Piskvor deixou a construção de
5

Sem junções, como você relacionará itens de pedidos com pedidos? Esse é o objetivo de um sistema de gerenciamento de banco de dados relacional. Sem junções, não há dados relacionais e você também pode usar arquivos de texto para processar dados.

Parece que ele não entende o conceito, então ele está tentando fazer parecer que eles são inúteis. Ele é o mesmo tipo de pessoa que acha que o Excel é um aplicativo de banco de dados. Dê um tapa nele e diga a ele para ler mais sobre bancos de dados. Fazer várias conexões e extrair dados e mesclar os dados via C # é a maneira errada de fazer as coisas.

JonH
fonte
5

Não entendo a lógica da instrução "junções no SQL são inúteis". É útil filtrar e limitar os dados antes de trabalhar nele? Como os outros respondentes afirmaram que é isso que os mecanismos de banco de dados fazem, deve ser no que eles são bons.

Talvez um programador preguiçoso se atenha às tecnologias com as quais está familiarizado e evite outras possibilidades por razões não técnicas.

Deixo para você decidir.

Jodrell
fonte
5

Vamos considerar um exemplo: uma tabela com registros de fatura e uma tabela relacionada com registros de itens de linha de fatura. Considere o pseudocódigo do cliente:

for each (invoice in invoices)
    let invoiceLines = FindLinesFor(invoice)
...

Se você tiver 100.000 faturas com 10 linhas cada, esse código procurará 10 linhas de fatura em uma tabela de 1 milhão e fará isso 100.000 vezes. À medida que o tamanho da tabela aumenta, o número de operações selecionadas aumenta, e o custo de cada operação de seleção aumenta.

Como os computadores são rápidos, você pode não notar uma diferença de desempenho entre as duas abordagens se tiver vários milhares de registros ou menos. Como o aumento de custo é mais do que linear, à medida que o número de registros aumenta (para milhões, digamos), você começará a notar uma diferença, e a diferença se tornará menos tolerável à medida que o tamanho do conjunto de dados aumentar.

A junção, no entanto. usará os índices da tabela e mesclará os dois conjuntos de dados. Isso significa que você está efetivamente digitalizando a segunda tabela uma vez, em vez de acessá-la aleatoriamente N vezes. Se houver uma chave estrangeira definida, o banco de dados já terá os links entre os registros relacionados armazenados internamente.

Imagine fazer isso sozinho. Você tem uma lista alfabética de alunos e um caderno com todos os relatórios das notas dos alunos (uma página por turma). O bloco de notas é classificado em ordem pelo nome dos alunos, na mesma ordem que a lista. Como você prefere continuar?

  1. Leia um nome da lista.
  2. Abra o notebook.
  3. Encontre o nome do aluno.
  4. Leia as notas do aluno, virando as páginas até chegar ao próximo aluno ou à última página.
  5. Feche o caderno.
  6. Repetir.

Ou:

  1. Abra o notebook na primeira página.
  2. Leia um nome da lista.
  3. Leia todas as notas para esse nome no caderno.
  4. Repita as etapas 2 a 3 até chegar ao fim
  5. Feche o caderno.
phoog
fonte
5

Parece um caso clássico de " Eu posso escrever melhor ". Em outras palavras, ele está vendo algo que vê como uma dor no pescoço (escrevendo várias junções no SQL) e dizendo "Tenho certeza de que posso escrever melhor e obter melhor desempenho". Você deve perguntar a ele se ele é a) mais inteligente eb) mais instruído do que a pessoa comum que conhece profundamente o código de otimização do Oracle ou SQL Server. As probabilidades são de que ele não é.

jcollum
fonte
3

Ele certamente está errado. Embora existam profissionais definidos para manipulação de dados em linguagens como C # ou Java, as junções são mais rápidas no banco de dados devido à natureza do próprio SQL.

O SQL continua detalhando estatísticas sobre os dados e, se você criou seus índices corretamente, pode encontrar rapidamente um registro em alguns milhões. Além do fato de que, por que você deseja arrastar todos os seus dados para o C # para fazer uma junção, basta fazê-lo no nível do banco de dados?

Os profissionais para usar o C # entram em ação quando você precisa fazer algo iterativamente. Se você precisar executar alguma função para cada linha, provavelmente será mais rápido fazê-lo no C #; caso contrário, a junção de dados será otimizada no banco de dados.

Mike M.
fonte
3

Vou dizer que me deparei com um caso em que era mais rápido quebrar a consulta e fazer as junções no código. Dito isto, foi apenas com uma versão específica do MySQL que eu tive que fazer isso. Tudo o resto, o banco de dados provavelmente será mais rápido (observe que talvez você precise otimizar as consultas, mas ainda será mais rápido).

JaCraig
fonte
3

Eu suspeito que ele tenha uma visão limitada sobre para que bancos de dados devem ser usados. Uma abordagem para maximizar o desempenho é ler todo o banco de dados na memória. Nessa situação, você pode obter um desempenho melhor e pode querer realizar junções se houver memória para obter eficiência. No entanto, isso realmente não está usando um banco de dados, como um IMHO de banco de dados.

Peter Lawrey
fonte
3
A maioria dos mecanismos de banco de dados fará isso por você nos bastidores; e, por exemplo, no MySQL, você pode criar uma tabela puramente na memória ( MEMORYmecanismo). Reimplementar a funcionalidade do banco de dados sem o banco de dados geralmente é um sinal de um caso grave de NIH;)
Piskvor deixou o prédio
@ Phoho: Não inventado aqui - em outras palavras, "eu não pensei nisso, então não existe". Muitas rodas quadradas foram reinventadas por causa disso. (e sim, às vezes, reinventar a roda é útil, por exemplo, se você estiver fabricando carros de corrida; reinventar "apenas porque" é improvável que você consiga uma roda melhor)
Piskvor saiu do prédio em
Em outras palavras, "eu não fiz isso, então deve ser lixo". Isso só tem verdade na medida em que "eu não testei para que não seja adequado para meus propósitos", então teste-o antes de julgá-lo.
Peter Peterrey
@Piskvor: Não necessariamente, o banco de dados pode usar apenas a memória do sistema em que é executado, enquanto o aplicativo pode usar a memória do servidor de aplicativos. Em outras palavras: se o banco de dados estiver em um host dedicado, o acesso a esse cache ainda exige largura de banda da rede e está sujeito à latência da rede, mas qualquer cache que o aplicativo mantenha pode ser consultado com a velocidade e baixa latência do acesso à memória.
meriton
2

Não, as junções não são apenas melhor otimizadas no código do banco de dados que C # / Java ad-hoc; mas geralmente várias técnicas de filtragem podem ser aplicadas, o que gera um desempenho ainda melhor.

Jonas Byström
fonte
2

Ele está errado, junta-se ao que os programadores competentes usam. Pode haver alguns casos limitados em que o método proposto é mais eficiente (e naqueles que eu provavelmente usaria um banco de dados Documant), mas não consigo vê-lo se você tiver uma quantidade enganosa de dados. Por exemplo, faça esta consulta:

select t1.field1 
from table1 t1
join table2 t2 
    on t1.id = t2.id
where t1.field2 = 'test'

Suponha que você tenha 10 milhões de registros na tabela1 e 1 milhão de registros na tabela2. Suponha que 9 milhões de registros na tabela 1 atendam à cláusula where. Suponha que apenas 15 deles estejam na tabela2 também. Você pode executar esta instrução sql que, se indexada corretamente, levará milissegundos e retornará 15 registros pela rede com apenas 1 coluna de dados. Ou você pode enviar dez milhões de registros com 2 colunas de dados e enviar separadamente outros 1 milhão de registros com uma coluna de dados pela rede e combiná-los no servidor da web.

Ou, é claro, você pode manter todo o conteúdo do banco de dados no servidor da Web o tempo todo, o que é simplesmente bobo se você tiver mais do que uma quantidade trivial de dados e dados que estão mudando continuamente. Se você não precisa das qualidades de um banco de dados relacional, não use um. Mas se você o fizer, use-o corretamente.

HLGEM
fonte
2

Eu ouvi esse argumento muitas vezes durante minha carreira como desenvolvedor de software. Quase sempre que foi declarado, o sujeito que fez a reclamação não tinha muito conhecimento sobre sistemas de bancos de dados relacionais, a maneira como eles funcionam e a forma como esses sistemas devem ser usados.

Sim, quando usado incorretamente , as junções parecem inúteis ou até perigosas. Porém, quando usado da maneira correta, existe muito potencial para a implementação do banco de dados executar otimizações e "ajudar" o desenvolvedor a recuperar o resultado correto com mais eficiência.

Não se esqueça de que usando um JOINvocê diz ao banco de dados como espera que os dados se relacionem entre si e, portanto, fornece ao banco de dados mais informações sobre o que você está tentando fazer e, portanto, é capaz de atender melhor às suas necessidades.

Portanto, a resposta é definitivamente: Não, JOINSnão é inútil!

perdian
fonte
0

Isso é "tecnicamente verdadeiro" apenas em um caso que não é usado com freqüência em aplicativos (quando todas as linhas de todas as tabelas nas junções são retornadas pela consulta). Na maioria das consultas, apenas uma fração das linhas de cada tabela é retornada. O mecanismo de banco de dados geralmente usa índices para eliminar as linhas indesejadas, às vezes mesmo sem ler a linha real, pois pode usar os valores armazenados nos índices. O mecanismo de banco de dados é ele próprio escrito em C, C ++ etc. e é pelo menos tão eficiente quanto o código escrito por um desenvolvedor.

Fred
fonte
0

A menos que eu tenha entendido seriamente, a lógica da pergunta é muito falha

Se houver 20 linhas em B para cada A, 1000 linhas em A implicarão 20k em B. Não pode haver apenas 100 linhas em B, a menos que haja muitas tabelas "AB" com 20k linhas contendo o mapeamento .

Portanto, para obter todas as informações sobre quais 20 das 100 linhas B são mapeadas para cada linha A, você também apresenta a tabela AB. Portanto, isso seria:

  • 3 conjuntos de resultados de 100, 1000 e 20k linhas e um cliente
  • um único conjunto de resultados JOIN A-AB-B com 20 mil linhas

Portanto, "JOIN" no cliente adiciona algum valor quando você examina os dados. Não que não seja uma má ideia. Se eu estava recuperando um objeto do banco de dados, talvez faça mais sentido decompô-lo em conjuntos de resultados separados. Para uma chamada do tipo relatório, eu a dividia em uma quase sempre.

De qualquer forma, eu diria que quase não há utilidade para uma junção cruzada dessa magnitude. É um péssimo exemplo.

Você precisa se juntar a algum lugar, e é nisso que o RDBMS é bom. Eu não gostaria de trabalhar com nenhum macaco de código de cliente que pense que pode fazer melhor.

Reflexão tardia:

Para ingressar no cliente, são necessários objetos persistentes, como DataTables (em .net). Se você tiver um conjunto de resultados nivelado, ele poderá ser consumido por algo mais leve, como um DataReader. Volume alto = muitos recursos do cliente usados ​​para evitar um JOIN do banco de dados.

gbn
fonte