Existem situações que exigem uma consulta muito grande juntando várias tabelas com instruções sub select nelas 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 todas de uma 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 fazê-lo?
Vou discordar de consultas grandes e complicadas com datagod aqui. Eu vejo isso apenas como problemas se eles forem desorganizados. Em termos de desempenho, quase sempre são melhores porque o planejador tem muito mais liberdade para recuperar as informações. No entanto, consultas grandes precisam ser escritas com a manutenção em mente. Em geral, descobri que SQL simples e bem estruturado é fácil de depurar, mesmo quando uma única consulta dura mais de 200 linhas. Isso ocorre porque geralmente você tem uma boa ideia do tipo de problema com o qual está lidando, portanto, há apenas algumas áreas na consulta que você precisa verificar.
Os problemas de manutenção, IME, surgem quando a estrutura do SQL quebra. Consultas longas e complexas em subseleçõ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 se você estiver no MySQL, as visualizações não funcionam muito bem, mas na maioria dos outros db's sim) e use expressões de tabela comuns onde elas não funcionam (o MySQL não suporta essas por falar nisso).
Consultas longas e complexas funcionam muito bem em um caso de manutenção e desempenho em que você mantém suas cláusulas where simples e em que faz o máximo possível com junções em vez de subseleções. O objetivo é fazer com que "os registros não apareçam" dê a você alguns lugares muito específicos na consulta para verificar (ele está sendo 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ê mencionou que isso é MySQL, então é improvável que as visualizações tenham um bom desempenho e os CTEs estão fora de questão. Além disso, o exemplo dado não é particularmente longo ou complexo, então não há problema.
Como alguém que precisa dar suporte/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 do desempenho, mas pelo menos 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 sobre você. Faça com que seja difícil para eles e eles vão amaldiçoar você.
Meus 2 centavos sobre as 2 palavras-chave desempenho e escalabilidade da consulta:
Desempenho de consulta: o paralelismo do SQL Server já faz um trabalho muito bom dividindo consultas em pesquisas multi-thread, então não tenho certeza de quanto de melhoria no desempenho de consulta você verá ao fazê-lo para o SQL Server. Você terá que olhar para o plano de execução para ver quanto grau de paralelismo você obtém ao executá-lo e comparar os resultados nos dois sentidos. Se você acabar tendo que usar uma dica de consulta para obter o mesmo desempenho ou melhor, IMO não vale a pena, pois a dica de consulta pode não ser ideal posteriormente.
Escalabilidade: Ler as consultas pode ser mais fácil como o datagod declarou, e dividi-las em consultas separadas faz sentido se você também puder usar suas novas consultas em outras áreas, mas se você não for usá-las para outras chamadas também, então serão ainda mais procs armazenados para gerenciar para 1 tarefa, e o IMO não contribuiria para a escalabilidade.
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
EXPLAIN
instrução com aSELECT
instrução. O número de rastreamentos/varreduras que seu banco de dados fará para buscar seus dados é o produto dos valores de "linhas" retornados por suaEXPLAIN
consulta. No nosso caso, tivemos uma consulta juntando 10 tabelas. Para um registro específico, o rastreamento totalizou 409 milhões que blogaram nosso banco de dados e aumentaram nosso uso de CPU de nosso servidor de banco de dados em mais de 300%. Conseguimos recuperar as mesmas informações dividindo as consultas muito mais rapidamente.Portanto, 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.