Pergunta

Tenho um grande banco de dados de dados de pedidos normalizados que está ficando muito lento para consultar relatórios.Muitas das consultas que utilizo em relatórios juntam cinco ou seis tabelas e precisam examinar dezenas ou centenas de milhares de linhas.

Existem muitas consultas e a maioria foi otimizada tanto quanto possível para reduzir a carga do servidor e aumentar a velocidade.Acho que é hora de começar a manter uma cópia dos dados em formato desnormalizado.

Alguma idéia sobre uma abordagem?Devo começar com algumas das minhas piores dúvidas e continuar a partir daí?

Foi útil?

Solução

Eu sei mais sobre mssql do que sobre mysql, mas não acho que o número de junções ou o número de linhas que você está falando deva causar muitos problemas com os índices corretos.Você analisou o plano de consulta para ver se está faltando algum?

http://dev.mysql.com/doc/refman/5.0/en/explain.html

Dito isto, uma vez que você esteja satisfeito com seus índices e tenha esgotado todos os outros caminhos, a desnormalização pode ser a resposta certa.Se você tiver apenas uma ou duas consultas que sejam problemáticas, uma abordagem manual provavelmente será apropriada, enquanto algum tipo de ferramenta de armazenamento de dados pode ser melhor para criar uma plataforma para desenvolver cubos de dados.

Aqui está um site que encontrei que aborda o assunto:

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

Aqui está uma técnica simples que você pode usar para simplificar a desnormalização de consultas, se estiver fazendo apenas algumas de cada vez (e não estou substituindo suas tabelas OLTP, apenas criando uma nova para fins de relatório).Digamos que você tenha esta consulta em sua aplicação:

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1

Você poderia criar uma tabela desnormalizada e preencher quase a mesma consulta:

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided)

Observe que os sublinhados correspondem aos aliases de tabela que você usa

insert tbl_ab select a.id, a.name, b.address from tbla a
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything

Em seguida, para corrigir seu aplicativo para usar a nova tabela desnormalizada, troque os pontos por sublinhados.

select a_name as name, b_address as address 
from tbl_ab where a_id = 1;

Para consultas grandes, isso pode economizar muito tempo e deixar claro de onde vieram os dados, e você pode reutilizar as consultas que já possui.

Lembre-se, estou defendendo isso apenas como último recurso.Aposto que existem alguns índices que podem ajudá-lo.E quando você desnormalizar, não se esqueça de levar em conta o espaço extra em seus discos e descobrir quando executará a consulta para preencher as novas tabelas.Provavelmente isso deve acontecer à noite ou sempre que a atividade estiver baixa.E os dados dessa tabela, é claro, nunca estarão exatamente atualizados.

[Mais uma edição] Não esqueça que as novas tabelas que você criar também precisam ser indexadas!A parte boa é que você pode indexar o que quiser e não se preocupar com a contenção do bloqueio de atualização, já que, além da inserção em massa, a tabela verá apenas seleções.

Outras dicas

MySQL 5 suporta Visualizações, o que pode ser útil neste cenário.Parece que você já otimizou bastante, mas se não, você pode usar o MySQL EXPLICAR sintaxe para ver quais índices estão realmente sendo usados ​​e o que está retardando suas consultas.

No que diz respeito à normalização de dados (esteja você usando visualizações ou apenas duplicando dados de uma maneira mais eficiente), acho que começar com as consultas mais lentas e avançar é uma boa abordagem.

Eu sei que isso é um pouco tangencial, mas você já tentou ver se há mais índices para adicionar?

Não tenho muita experiência em banco de dados, mas tenho trabalhado muito com bancos de dados recentemente e tenho descoberto que muitas consultas podem ser melhoradas apenas adicionando índices.

Estamos usando o DB2 e há um comando chamado db2expln e db2advis, o primeiro indicará se varreduras de tabela versus varreduras de índice estão sendo usadas e o segundo recomendará índices que você pode adicionar para melhorar o desempenho.Tenho certeza que o MySQL tem ferramentas semelhantes ...

De qualquer forma, se isso é algo que você ainda não considerou, tem me ajudado muito...mas se você já seguiu esse caminho, acho que não é o que você está procurando.

Outra possibilidade é uma "visão materializada" (ou como é chamada no DB2), que permite especificar uma tabela que é essencialmente construída com partes de múltiplas tabelas.Assim, em vez de normalizar as colunas reais, você poderia fornecer esta visão para acessar os dados...mas não sei se isso tem impactos graves no desempenho em inserções/atualizações/exclusões (mas se for "materializado", deve ajudar nas seleções, já que os valores são armazenados fisicamente separadamente).

De acordo com alguns dos outros comentários, eu definitivamente daria uma olhada em sua indexação.

Uma coisa que descobri no início deste ano em nossos bancos de dados MySQL foi o poder dos índices compostos.Por exemplo, se você estiver relatando números de pedidos em intervalos de datas, um índice composto nas colunas de número e data do pedido pode ajudar.Acredito que o MySQL só pode usar um índice para a consulta, portanto, se você tivesse índices separados no número e na data do pedido, teria que decidir usar apenas um deles.Usar o comando EXPLAIN pode ajudar a determinar isso.

Para dar uma indicação do desempenho com bons índices (incluindo vários índices compostos), posso executar consultas juntando 3 tabelas em nosso banco de dados e obter resultados quase instantâneos na maioria dos casos.Para relatórios mais complexos, a maioria das consultas é executada em menos de 10 segundos.Essas 3 tabelas possuem 33 milhões, 110 milhões e 140 milhões de linhas respectivamente.Observe que também já havíamos normalizado isso um pouco para acelerar nossa consulta mais comum no banco de dados.

Mais informações sobre suas tabelas e os tipos de consultas de relatórios podem permitir sugestões adicionais.

Para MySQL eu gosto desta palestra: Rede do mundo real:Desempenho e escalabilidade, edição MySQL.Ele contém vários conselhos diferentes para obter mais velocidade do MySQL.

Você também pode considerar selecionar uma tabela temporária e, em seguida, realizar consultas nessa tabela temporária.Isso evitaria a necessidade de reunir novamente suas tabelas para cada consulta emitida (assumindo que você possa usar a tabela temporária para inúmeras consultas, é claro).Isso basicamente fornece dados desnormalizados, mas se você estiver fazendo apenas chamadas selecionadas, não há preocupação com a consistência dos dados.

Além da minha resposta anterior, outra abordagem que adotamos em algumas situações é armazenar os principais dados dos relatórios em tabelas de resumo separadas.Existem certas consultas de relatórios que serão lentas mesmo após a desnormalização e otimizações e descobrimos que criar uma tabela e armazenar totais em execução ou informações resumidas ao longo do mês, à medida que chegavam, também tornava os relatórios de final de mês muito mais rápidos.

Achamos essa abordagem fácil de implementar, pois não quebrava nada que já estava funcionando - são apenas inserções adicionais de banco de dados em determinados pontos.

Tenho brincado com índices compostos e tenho visto alguns benefícios reais... talvez eu faça alguns testes para ver se isso pode me salvar aqui... pelo menos por mais um pouco.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top