Stockage vs calcul des valeurs globales

96

Existe-t-il des directives ou des règles empiriques permettant de déterminer quand stocker les valeurs agrégées et quand les calculer à la volée?

Par exemple, supposons que j'ai des widgets que les utilisateurs peuvent évaluer (voir le schéma ci-dessous). Chaque fois que j'affiche un widget, je peux calculer la note moyenne des utilisateurs à partir du Ratingstableau. Sinon, je pourrais stocker la note moyenne sur la Widgettable. Cela m'éviterait de devoir calculer la note chaque fois que j'afficherai le widget, mais je devrais alors recalculer la note moyenne chaque fois qu'un utilisateur évaluait un widget.

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

Réponses:

58

Ça dépend. Le précalcul des valeurs agrégées impose une charge plus importante aux écritures; leur dérivation rend les lectures plus difficiles

Si vous accédez fréquemment à une valeur dérivée, le pré-calcul est une étape de dé-normalisation valide. Cependant, dans ce cas, je recommande d'utiliser une vue matérialisée (une vue, écrite sur le disque, liée par un déclencheur aux tables parent). La vue matérialisée est conçue pour stocker des données fréquemment demandées mais fastidieuses, et elle est utile pour les grands nombres d'écritures et les faibles nombres de lectures.

Dans un scénario à écriture élevée et lecture élevée, envisagez d’avoir une tâche en arrière-plan qui imite les effets d’une vue matérialisée, mais en moins qu’en temps réel. Cela présentera une moyenne "assez bonne" tout en préservant les performances d'écriture et de lecture.

En aucun cas, vous ne devriez traiter la colonne dérivée comme une colonne "normale": assurez-vous que les données présentées dans la "vue" des widgets sont présentes ailleurs dans le tableau, de sorte que le tuple entier puisse être dérivé par tous les processus que vous avez créés. Cette question est également fortement spécifique à la base de données (et à la version de la base de données). Je recommande donc de tester les performances de l'agrégat (avec les index appropriés) par rapport à un ensemble de données de taille normale et à la vue matérialisée.

Brian Ballsun-Stanton
la source
J'ai trouvé cette discussion très utile en ce qui concerne les vues matérialisées. Il est conçu pour Oracle, mais peut être compris de manière générique. Pour ceux qui, comme moi, sont issus de MySQL, une vue MySQL est différente d'une vue matérialisée, elle est virtuelle et ne se stocke pas sur disque (comme indiqué dans le lien que j'ai fourni).
Siddhartha
upvoted! était sur le point de poser la question exacte, j'ai besoin de stocker des indicateurs tels que SMA, EMA, WMA, RSI, etc., et ils impliquent des calculs lourds. les nouvelles données qui arrivent, quelle est la bonne stratégie pour les maintenir, je sais que les vues vont complètement déchirer la base de données si tout le monde commence à interroger les vues à gauche et à droite
PirateApp
11

À quelle fréquence devez-vous calculer / afficher les valeurs par rapport à la fréquence de modification / mise à jour des nombres sous-jacents?

Ainsi, si vous avez un site Web avec 10 000 hits quotidiens affichant une valeur qui ne changera qu'une fois par heure, je le calculerais lorsque les valeurs sous-jacentes changeraient (pourrait être un déclencheur de base de données, par exemple).

Si vous avez un outil pour consulter les statistiques, où les statistiques changent à la seconde, mais que trois personnes seulement ont accès, et qu'elles ne le consultent que quelques fois par jour, je serais plus susceptible de calculer à la volée. (à moins que cela ne prenne quelques minutes à calculer qu'avoir des données obsolètes en premier lieu n'est pas grave ... et mon patron me dit de générer simplement le problème à partir de cron toutes les heures, pour qu'il n'ait pas attendre quand il veut le regarder.)

Joe
la source
toutes les 15 minutes, 10 mesures qui changent de 100% à 1 000 lignes par mesure
PirateApp
1
@PirateApp et combien de fois est-il visualisé dans une fenêtre moyenne de 15 minutes? Ce que vous pouvez également faire, c'est le générer à la première demande dans une fenêtre de 15 minutes, puis le mettre en cache pour les personnes qui ne cessent de recharger
Joe
il sera sur un site Web, donc je suppose qu'au moins 10000 personnes le verront pour commencer, le site n'est pas en ligne, alors ne disposez pas de données réelles sur le comportement des utilisateurs
PirateApp
1
La question est de savoir combien de demandes sont relatives à la fréquence à laquelle elles changent. Donc, si vous pré-générez quelque chose qui sera vu 10 000 fois avant que les données sous-jacentes ne changent, alors oui, pré-générez-le. Si cela n'est visionné qu'une fois ou moins d'une fois (parce que les données changent si rapidement ou que la page est rarement consultée), vous ne le faites pas.
Joe
4

Utilisez la table StaleWidgets en tant que file d'attente de widgets "non valides" (à recalculer). Utilisez une autre tâche (asynchrone) pouvant recalculer ces valeurs. La période ou le moment du recalcul dépend de la configuration système requise:

  • juste en lecture,
  • à la fin du mois,
  • pour certains utilisateurs en début de journée
  • ...
garik
la source
1
Comment entrent-ils dans la file d'attente périmée alors?
jcolebrand
2
@jcolebrand ..au moment d'insérer / de supprimer une évaluation (tableau d'évaluation) pour un widget. À ce moment, la valeur moyenne de la table des widgets devient invalide. Nous devons donc insérer dans la table un enregistrement StaleWidgets comportant une seule colonne - widget_id. Utilisez un déclencheur ou un proc stocké qui insère l'enregistrement dans la table des évaluations ou dans votre variante bien sûr.
Garik
2

Je suggérerais de calculer à la volée si le calcul n'est pas trop lourd et dans le cas où vous avez une calcul complexe et des mises à jour fréquentes mais pas cette fréquence de lecture que vous pouvez stocker des données calculées et avoir une colonne supplémentaire (bool) qui stockera si un recalcul est requis ou non. . Par exemple, définissez cette colonne sur true chaque fois qu'un recalcul doit être effectué, mais ne le recalculez pas et définissez cette colonne sur false (cela représentera la dernière valeur calculée et non obsolète).

De cette façon, vous ne devez pas recalculer à chaque fois, vous calculerez uniquement lorsque vous devez lire et recalculer la valeur de la colonne est vraie. De cette façon, vous économiserez beaucoup de recalcul.

techExplorer
la source
2

Pour le cas en particulier, il existe une solution différente selon laquelle il n'est pas nécessaire d'ajouter toutes les cotes et de la diviser par le total pour obtenir la moyenne. Au lieu de cela, vous pouvez avoir un autre champ contenant le total des avis. Ainsi, chaque fois que vous ajoutez un classement, vous calculez la nouvelle moyenne à l'aide de (avg_rating × total + new_rating) / total, ce qui est beaucoup plus rapide que l'agrégat et réduit les lectures de disque ne pas avoir à accéder à toutes les valeurs d'évaluation. Des solutions similaires pourraient s'appliquer à d'autres cas.

L'inconvénient est que ce n'est pas une transaction acide, vous pouvez donc vous retrouver avec une notation obsolète. Mais vous pouvez toujours résoudre ce problème en utilisant des déclencheurs dans la base de données. L'autre problème est que la base de données n'est plus normalisée, mais n'ayez pas peur de dénormaliser les données en échange de performances.

Adrian Martinez
la source