O que é mais rápido, uma consulta grande ou muitas consultas pequenas?

68

Eu tenho trabalhado para diferentes empresas e notei que algumas delas preferem ter visões que se juntarão a uma mesa com todos os seus "parentes". Mas no aplicativo algumas vezes, precisamos usar apenas 1 coluna.

Então, seria mais rápido fazer seleções simples e depois "juntá-las" ao código do sistema?

O sistema pode ser php, java, asp, qualquer idioma que se conecte ao banco de dados.

Portanto, a questão é: o que é mais rápido passar do lado do servidor (php, java, asp, ruby, python ...) para o banco de dados, execute uma consulta que obtenha tudo o que precisamos ou do lado do servidor para o banco de dados e execute um consulta que obtém apenas as colunas de uma tabela por vez?

sudo.ie
fonte
2
Qual implementação de 'SQL' você está usando? MySQL, Microsoft SQL Server, Oracle, Postgresql, etc? Atualize sua tag.
RLF
11
Mysql e Postgresql
sudo.pt
6
Minha experiência é que o MySQL não gosta de consultas complicadas e geralmente é mais rápido com consultas muito simples (mas mais). O otimizador de consultas do Postgres é muito melhor e geralmente é mais eficiente executar uma única consulta grande.
A_horse_with_no_name
3
@a_horse_with_no_name Essa é uma generalização muito ampla, especialmente no contexto desta pergunta. O otimizador do MySQL é realmente muito simples por design e pode causar problemas com junções e subconsultas - especialmente em versões mais antigas do MySQL - que produzem planos mais rápidos no PostgreSQL, enquanto o MySQL pode ser muito rápido para cargas OLTP puras. No entanto, no contexto da pergunta, uma única consulta grande será mais rápida que, digamos - no pior cenário possível - um SELECT dentro de um loop de programação (não importa o RDBMS usado).
jynus
2
@ jynus: bem, a pergunta é muito ampla (mais: eu disse "na minha experiência" - outras pessoas podem ter experiências diferentes). Uma consulta dentro de um LOOP nunca é uma boa ideia e quase sempre resulta de um design ruim ou falta de compreensão de como trabalhar com um banco de dados relacional.
A_horse_with_no_name

Respostas:

69

O que abordaria sua pergunta é o assunto JOIN DECOMPOSITION.

De acordo com a página 209 do livro

MySQL de alto desempenho

Você pode decompor uma associação executando várias consultas de tabela única em vez de uma associação multititulada e executando a associação no aplicativo. Por exemplo, em vez desta consulta única:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

Você pode executar estas consultas:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

Por que diabos você faria isso? Parece um desperdício à primeira vista, porque você aumentou o número de consultas sem receber nada em troca. No entanto, essa reestruturação pode realmente oferecer vantagens significativas de desempenho:

  • O armazenamento em cache pode ser mais eficiente. Muitos aplicativos armazenam em cache "objetos" que são mapeados diretamente para as tabelas. Neste exemplo, se o objeto com a tag mysqljá estiver armazenado em cache, o aplicativo ignorará a primeira consulta. Se você encontrar postagens com um ID 123, 567 ou 908 no cache, poderá removê-las da IN()lista. O cache de consulta também pode se beneficiar dessa estratégia. Se apenas uma das tabelas mudar com frequência, a decomposição de uma junção poderá reduzir o número de invalidações de cache.
  • Às vezes, executar as consultas individualmente pode reduzir a contenção de bloqueio
  • A realização de junções no aplicativo facilita o dimensionamento do banco de dados, colocando tabelas em diferentes servidores.
  • As consultas em si podem ser mais eficientes. Neste exemplo, o uso de uma IN()lista em vez de uma junção permite que o MySQL classifique os IDs das linhas e recupere as linhas da maneira mais otimizada possível com uma junção.
  • Você pode reduzir acessos de linhas redundantes. Fazer uma junção no aplicativo significa recuperar cada linha apenas uma vez., Enquanto uma junção na consulta é essencialmente uma desnormalização que pode acessar repetidamente os mesmos dados. Pelo mesmo motivo, essa reestruturação também pode reduzir o tráfego total da rede e o uso de memória.
  • Até certo ponto, você pode ver esta técnica como implementando manualmente uma junção de hash em vez do algoritmo de loops aninhados que o MySQL usa para executar uma junção. Uma junção de hash pode ser mais eficiente.

Como resultado, associações de ações no aplicativo podem ser mais eficientes quando você armazena em cache e reutiliza muitos dados de consultas anteriores, distribui dados em vários servidores, substitui associações por IN()listas ou uma associação se refere à mesma tabela várias vezes.

OBSERVAÇÃO

Gosto do primeiro marcador porque o InnoDB é um pouco pesado quando verifica o cache da consulta.

Quanto ao último marcador, escrevi uma postagem em 11 de março de 2013 ( existe uma diferença de execução entre uma condição JOIN e uma condição WHERE? ) Que descreve o algoritmo de loop aninhado. Depois de ler, você verá o quão boa pode ser a decomposição da junção.

Quanto a todos os outros pontos do livro , os desenvolvedores realmente buscam o desempenho como resultado final. Alguns contam com meios externos (fora do aplicativo) para aprimoramentos de desempenho, como usar um disco rápido, obter mais CPUs / Núcleos, ajustar o mecanismo de armazenamento e ajustar o arquivo de configuração. Outros se prenderão e escreverão um código melhor. Alguns podem recorrer à codificação de toda a inteligência de negócios em Procedimentos armazenados, mas ainda não aplicar a decomposição de junção (consulte Quais são os argumentos contra ou para colocar a lógica do aplicativo na camada do banco de dados? Junto com as outras postagens). Tudo depende da cultura e tolerância de cada loja de desenvolvedores.

Alguns podem ficar satisfeitos com o desempenho e não tocar mais no código. Outros simplesmente não percebem que há grandes benefícios que se pode colher se tentarem ingressar na composição.

Para os desenvolvedores que estão dispostos ...

DE UMA CHANCE !!!

RolandoMySQLDBA
fonte
3
Quanto ao link sobre como mudar para três consultas ... Conheço e respeito Baron, Vadim e Peter, mas discordo dessa sugestão enganosa. A maioria dos argumentos a favor da cisão é tão rara que nem vale a pena mencionar. Atenha-se a uma única consulta com JOINs, depois vamos trabalhar para melhorá-lo.
Rick James
2
@ RickJames Concordo com o espírito do seu comentário. Ao longo dos anos, vi trabalhos de decomposição de junções para alguns e falhar para outros. Mesmo com o conjunto de habilidades SQL adequado, isso poderia funcionar contra você se a decomposição da junção não for feita corretamente. No meu atual empregador, muitos representantes adoram aumentar e diminuir o tamanho, especialmente quando o código legado está envolvido e bolsos profundos estão disponíveis. Para aqueles que têm sabor de caviar, mas orçamentos de salada de ovo, a decomposição da junção pode valer o risco, mas deve ser feita corretamente.
RolandoMySQLDBA
Eu adoraria ver como isso funciona em um ambiente Oracle, se eu tivesse direitos e tempo.
Rick Henderson
Uma outra maneira de ser mais rápido é que, se você estiver fazendo pedidos, serão menos cálculos no geral encomendar listas menores do que pedir uma lista grande.
Evan Siroky
24

No Postgres (e provavelmente qualquer RDBMS em uma extensão semelhante, MySQL em menor extensão), menos consultas são quase sempre muito mais rápidas.

A sobrecarga de analisar e planejar várias consultas já é mais do que qualquer ganho possível na maioria dos casos.

Para não falar de trabalho adicional a ser feito no cliente, combinando os resultados, o que normalmente é muito mais lento. Um RDBMS é especializado nesse tipo de tarefa e operações são baseadas em tipos de dados originais. Sem conversão para textresultados intermediários ou transformação para tipos nativos do cliente, o que pode levar a resultados menos corretos (ou incorretos!). Pense em números de ponto flutuante ...

Você também transfere mais dados entre o servidor DB e o cliente. Isso pode ser insignificante para uma mão cheia de valores ou fazer uma enorme diferença.

Se várias consultas significam várias viagens de ida e volta para o servidor de banco de dados, você também coleta várias vezes a latência da rede e a sobrecarga da transação, possivelmente até a sobrecarga da conexão. Grande, grande perda.

Dependendo da sua configuração, a latência da rede sozinha pode levar mais tempo do que o resto em ordens de magnitude.

Pergunta relacionada sobre SO:

Pode haver um ponto de virada para consultas muito grandes e de longa execução, porque as transações coletam bloqueios nas linhas do banco de dados no caminho. Consultas muito grandes podem conter muitos bloqueios por um longo período de tempo, o que pode causar atrito com consultas simultâneas .

Erwin Brandstetter
fonte
Por curiosidade, o que você considera muito grande ?
Sablefoste
@ Sablefoste: Depende muito dos seus padrões de acesso. Um ponto crítico é onde as transações simultâneas começam a ser enfileiradas, aguardando a liberação de bloqueios ou se você acumular bloqueios suficientes para consumir uma parte substancial de seus recursos. Ou se suas consultas durarem o suficiente para interferir com o autovacuum ...
Erwin Brandstetter
Mas se tomarmos uma situação um tanto típica - uma consulta que usa uma junção externa e retorna muitos dados redundantes para a tabela "pai", que deve ser analisada e classificada pelo aplicativo (provavelmente alguma biblioteca ORM) versus uma seleção pequena que busca primeiro todos os IDs necessários e, em seguida, outra seleção menor com IN () em vez de junção externa? A segunda abordagem não será mais eficiente (considerando a largura de banda da CPU e da comunicação consumida pelo DB e pelo aplicativo)?
#
11
@JustAMartin: Parece o tipo de consulta quase certamente mais rápida quando tratada pelo planejador de consultas do RDBMS - assumindo consultas corretas. A respeito returns lots of redundant data for "parent" table: por que você retornaria dados redundantes? Retorne apenas os dados necessários.
Erwin Brandstetter
11
Com junção externa, o RDBMS retorna dados da tabela pai duplicados para cada filho ingressado, o que significa alguma sobrecarga de rede e memória e, em seguida, algumas análises adicionais na ferramenta ORM para jogar fora os valores pai duplicados e manter apenas um pai com n filhos. Portanto, com a consulta única, economizamos no trabalho eficiente do planejador de consultas RDBMS, menos solicitações de rede (ou canal local), mas perdemos na carga útil desnecessária adicional e na troca de dados na biblioteca ORM. Eu acho que é como sempre - meça antes de otimizar.
precisa saber é o seguinte