Armazenando vs calculando valores agregados

96

Existem diretrizes ou regras práticas para determinar quando armazenar valores agregados e quando calculá-los em tempo real?

Por exemplo, suponha que eu tenha widgets que os usuários possam avaliar (consulte o esquema abaixo). Cada vez que mostro um widget, posso calcular a classificação média do usuário a partir da Ratingstabela. Como alternativa, eu poderia armazenar a classificação média na Widgetmesa. Isso me pouparia de ter que calcular a classificação toda vez que eu exibir o widget, mas teria que recalcular a classificação média cada vez que um usuário classificasse um widget.

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question
BenV
fonte

Respostas:

58

Depende. Pré-calcular valores agregados coloca uma carga maior nas gravações, derivá-las torna as leituras mais difíceis

Se você está acessando com frequência um valor derivado, o pré-cálculo é uma etapa de desnormalização válida. No entanto, neste caso, recomendo usar uma Visualização Materializada (uma visualização gravada em disco, vinculada por gatilho às tabelas pai). A visualização materializada foi projetada para armazenar dados solicitados com frequência, mas tediosos de derivar, e é útil para altos números de gravações e baixos números de leituras.

Em um cenário de alta gravação e alta leitura, considere ter uma tarefa em segundo plano que imite os efeitos de uma exibição materializada, mas em menos que em tempo real. Isso apresentará uma média "boa o suficiente", preservando o desempenho de gravação e leitura.

Em nenhuma circunstância, você deve tratar a coluna derivada como uma coluna "normal": verifique se os dados apresentados na "visualização" Widgets estão presentes em outras partes da tabela, para que toda a tupla possa ser derivada por quaisquer processos que você substitua. Essa pergunta também é fortemente específica do banco de dados (e da versão do banco de dados), portanto, recomendo o teste de desempenho do agregado (com índices apropriados) em relação a um conjunto de dados de tamanho normal e à exibição materializada.

Brian Ballsun-Stanton
fonte
Achei esta discussão muito útil em relação às visualizações Materializadas. É adaptado ao Oracle, mas pode ser entendido genericamente. Para aqueles como eu, que vieram de um histórico do MySQL, uma visão do MySQL é diferente da visão Materializada, é virtual e não é armazenada em disco (como mencionado no link que eu forneci).
Siddhartha
votado! estava prestes a fazer a pergunta exata, preciso armazenar indicadores como SMA, EMA, WMA, RSI etc. e envolvem computação pesada, eu estava fazendo uma tabela atualmente que eu estava atualizando manualmente até agora, esses indicadores mudam 100% sempre novos dados chegando, o que é uma boa estratégia para mantê-las, eu sei visualizações vai rasgar completamente o banco de dados distante se todo mundo começa a consultar os pontos de vista esquerda e direita
PirateApp
11

Com que frequência você precisa calcular / exibir os valores em relação à frequência com que os números subjacentes são alterados / atualizados.

Portanto, se você tem um site com 10 mil acessos diários que exibe um valor que muda apenas uma vez por hora, eu o calcularia quando os valores subjacentes mudarem (pode ser um gatilho de banco de dados, o que seja).

Se você tiver uma ferramenta para analisar as estatísticas, onde as estatísticas estão mudando a cada segundo, mas você apenas três pessoas tiverem acesso, e elas apenas a visualizarão algumas vezes por dia, seria mais provável que eu calculasse na mosca. (a menos que demore alguns minutos para calcular que ter dados obsoletos em primeiro lugar não é grande coisa ... e meu chefe me diz para gerar a coisa do cron a cada hora, para que ele não tenha esperar quando ele quiser dar uma olhada.)

Joe
fonte
a cada 15 minutos, 10 métricas que mudam de 100% com 1000 linhas por métrica
PirateApp
1
@PirateApp e quantas vezes é visualizado em uma janela média de 15 minutos? O que você também pode fazer é gerá-lo no primeiro pedido em uma janela 15min e depois armazená-lo para as pessoas que mantêm bater recarregar uma e outra
Joe
ele estará disponível em um site, portanto, suponho que pelo menos 10000 pessoas o visualizem para iniciantes, o site não está
ativo
1
O problema é quantas solicitações em relação à frequência com que muda. Portanto, se você pré-gerar algo que será visto 10.000 vezes antes da alteração dos dados subjacentes, sim, pré-gere-o. Se ele for visualizado apenas uma vez ou menos de uma vez (porque os dados mudam muito rapidamente ou porque a página raramente é vista), você não o faz.
Joe
4

Use a tabela StaleWidgets como uma fila de widgets "inválidos" (a serem recalculados). Use outra tarefa de encadeamento (assíncrona) que possa recalcular esses valores. O período ou momento dos recálculos depende dos requisitos do sistema:

  • apenas na leitura,
  • no final do mês,
  • para algum usuário no início do dia
  • ...
garik
fonte
1
Como eles entram na fila obsoleta?
jcolebrand
2
@jcolebrand .. no momento de inserir / excluir a classificação (tabela de classificações) para algum widget. Neste momento, o valor médio na tabela Widgets está se tornando inválido, portanto, precisamos inserir na tabela o registro StaleWidgets que possui apenas uma coluna - widget_id. Use gatilho ou processo armazenado que insere registro na tabela Classificações ou na sua variante, é claro.
garik
2

Eu sugeriria o cálculo em tempo real se o cálculo não for muito complicado e, no caso de você ter uma cálculo complexo e uma atualização frequente, mas não a leitura de frequnet, você poderá armazenar dados calculados e ter uma coluna extra (bool) que armazenará se o recálculo é necessário ou não . por exemplo, defina esta coluna como true sempre que o recálculo for feito, mas não faça o recálculo e, quando você fizer o recálculo, defina esta coluna como falsa (isso representará que o valor calculado é o mais recente e não obsoleto).

Dessa forma, você não precisa recalcular todas as vezes, apenas calculará quando precisar ler e o valor da coluna de recálculo for verdadeiro. Dessa forma, você economizará muito recálculo.

techExplorer
fonte
2

Para o caso em particular, existe uma solução diferente em que você não precisa adicionar todas as classificações e dividi-las pelo total para encontrar a média. Em vez disso, você pode ter um outro campo que contém o total de revisões, portanto, toda vez que você adiciona uma classificação, calcula a nova média usando (avg_rating × total + new_rating) / total, isso é muito mais rápido que o agregado e reduz as leituras de disco desde que você não precisa acessar todos os valores de classificação. Soluções semelhantes podem se aplicar a outros casos.

A desvantagem disso é que não se trata de uma transação ácida; portanto, você pode terminar com uma classificação desatualizada. Mas ainda assim você pode resolver isso usando gatilhos no banco de dados. O outro problema é que o banco de dados não é mais normalizado, mas não tenha medo de desnormalizar os dados em troca do desempenho.

Adrian Martinez
fonte