É melhor separar uma grande consulta em várias consultas menores?

13

Há situações em que é necessário ter uma consulta realmente grande unindo várias tabelas com instruções sub-select para produzir os resultados desejados.

Minha pergunta é: devemos considerar o uso de várias consultas menores e trazer as operações lógicas para a camada de aplicativo consultando o banco de dados em mais de uma chamada ou é melhor tê-las de uma só vez?
Por exemplo, considere a seguinte consulta:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

Qual é a melhor maneira de fazer isso?

Hamed Momeni
fonte

Respostas:

14

Vou discordar de consultas grandes e complicadas com o datagod aqui. Eu os vejo apenas como problemas se estiverem desorganizados. Em termos de desempenho, esses quase sempre são melhores porque o planejador tem muito mais liberdade em como recuperar as informações. No entanto, grandes consultas precisam ser escritas com a manutenção em mente. Em geral, descobri que o SQL simples e bem estruturado é fácil de depurar, mesmo quando uma única consulta continua para mais de 200 linhas. Isso ocorre porque geralmente você tem uma boa idéia do tipo de problema com o qual está lidando, portanto, há apenas algumas áreas na consulta que você deve verificar.

Os problemas de manutenção, IME, aparecem quando a estrutura do SQL se decompõe. Consultas longas e complexas nas sub-seleções prejudicam a legibilidade e a solução de problemas, assim como as exibições em linha, e ambas devem ser evitadas em consultas longas. Em vez disso, use VIEWs, se puder (observe que, se você estiver no MySQL, os modos de exibição não têm um desempenho tão bom, mas na maioria dos outros bancos de dados), e use expressões de tabela comuns onde elas não funcionam (o MySQL não suporta esses btw).

Consultas longas e complexas funcionam muito bem tanto no caso de manutenção quanto no desempenho, onde você mantém suas cláusulas where simples e onde você faz o máximo possível com junções em vez de subselecionações. O objetivo é fazer com que "os registros não apareçam" forneça alguns locais muito específicos na consulta para verificar (será descartado em uma junção ou filtrado em uma cláusula where?) E, assim, a equipe de manutenção pode realmente manter as coisas.

Em relação à escalabilidade, lembre-se de que quanto mais flexibilidade o planejador tiver, isso também é bom.

Edit: Você menciona que este é o MySQL, portanto, é improvável que as visualizações tenham um desempenho tão bom e as CTEs estejam fora de questão. Além disso, o exemplo dado não é particularmente longo ou complexo, portanto não há problema.

Chris Travers
fonte
Nota: Eu tive consultas (não no MySQL, mas ainda assim ...) que eram longas e complexas o suficiente para que os planos de consulta gerados não fossem ótimos. Nesses casos, é possível obter resultados mais rápidos, dividindo uma consulta extremamente complexa em duas consultas menos complexas. Dito isto, é raro, e geralmente escreverei a consulta complexa e descobrirei se há um problema em vez de dividir a consulta em pedaços menores preventivamente.
RDFozz
8

Como alguém que precisa apoiar / limpar essas consultas grandes e complicadas, eu diria que é muito melhor separá-las em vários pequenos pedaços fáceis de entender. Não é necessariamente melhor do ponto de vista de desempenho, mas você está dando ao SQL uma chance melhor de apresentar um bom plano de consulta.

Facilite a vida das pessoas que o seguem, e elas dirão coisas boas a seu respeito. Torne difícil para eles e eles o amaldiçoarão.

datagod
fonte
2
a desvantagem de uma série de consultas simples é que o estado muda significativamente entre elas, tornando a depuração geral do aplicativo mais complexa. Ou seja, você pode depurar grandes consultas SQL frequentemente como árvores, mas o código do aplicativo obtém uma instrução depurada por instrução, verificando como o estado muda nas instruções. Os verdadeiros problemas têm a ver com o fato de que subselects e pontos de vista em linha são também as suas próprias árvores .....
Chris Travers
No meu caso, o único que precisa gerenciar o banco de dados e o código sou eu. E principalmente a minha pergunta era sobre o desempenho apontar a consulta.
Hamed Momeni
Vocês teriam que dar uma olhada na maneira como escrevo meus grandes processos em lote. Divida as coisas em consultas simples e muito fáceis de ler. Sou tendencioso porque as consultas que acabo tentando arrumar têm rotineiramente mais de 1000 linhas.
datagod
5

Meus 2 centavos nas 2 palavras-chave consulta desempenho e escalabilidade:

Desempenho da consulta: o paralelismo do SQL Server já faz um trabalho muito bom, dividindo as consultas em pesquisas multithread, por isso não tenho certeza do quanto de melhoria no desempenho da consulta você verá ao fazê-lo no SQL Server. Você precisará examinar o plano de execução para ver quanto grau de paralelismo você obtém ao executá-lo, no entanto, e comparar os resultados nos dois sentidos. Se você precisar usar uma dica de consulta para obter o mesmo ou melhor desempenho, o IMO não valerá a pena, pois a dica de consulta pode não ser ideal posteriormente.

Escalabilidade: a leitura das consultas pode ser mais fácil, como indicado no código de dados, e dividi-las em consultas separadas faz sentido se você pode usar suas novas consultas em outras áreas também, mas se não for usá-las para outras chamadas também, serão ainda mais procs armazenados para gerenciar uma tarefa, e a IMO não contribuirá para a escalabilidade.

Ali Razeghi
fonte
2
RE: "SQL Server" faz referência, embora o OP não tenha especificado nenhum RDBMS em particular. Suspeito que eles estejam no MySQL pelos ticks back eLIMIT
Martin Smith
@MartinSmith Você suspeita corretamente. É o MySQL.
Hamed Momeni 23/02
2

Algumas vezes, não há escolha a não ser dividir a consulta grande / complexa em consultas pequenas. A melhor maneira de determinar isso seria usar a EXPLAINdeclaração com a SELECTdeclaração. O número de rastreamentos / verificações que seu banco de dados fará para buscar seus dados é o produto dos valores de "linhas" retornados por sua EXPLAINconsulta. No nosso caso, tivemos uma consulta juntando 10 tabelas. Por um registro específico, o rastreamento totalizou 409 milhões de blogs no nosso banco de dados e aumentou o uso da CPU do servidor de banco de dados em mais de 300%. Conseguimos recuperar as mesmas informações dividindo as consultas muito mais rapidamente.

Portanto, em suma, em alguns casos, dividir uma consulta complexa / grande faz sentido, mas em outros pode levar a muitos problemas de desempenho ou manutenção e isso deve ser tratado caso a caso.

user140665
fonte