Speichern oder Berechnen von Aggregatwerten

96

Gibt es Richtlinien oder Faustregeln, die festlegen, wann Aggregatwerte gespeichert und wann sie im laufenden Betrieb berechnet werden sollen?

Angenommen, ich habe Widgets, die Benutzer bewerten können (siehe Schema unten). Jedes Mal, wenn ich ein Widget anzeige, kann ich die durchschnittliche Benutzerbewertung aus der RatingsTabelle berechnen . Alternativ könnte ich die Durchschnittsbewertung auf dem WidgetTisch speichern . Dies erspart mir die Berechnung der Bewertung jedes Mal, wenn ich das Widget anzeige. Dann müsste ich die durchschnittliche Bewertung jedes Mal neu berechnen, wenn ein Benutzer ein Widget bewertet.

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

Antworten:

58

Es hängt davon ab, ob. Durch die Vorberechnung von Aggregatwerten werden Schreibvorgänge stärker belastet und das Ableiten von Lesevorgängen erschwert

Wenn Sie häufig auf einen abgeleiteten Wert zugreifen, ist die Vorberechnung ein gültiger De-Normalisierungsschritt. In diesem Fall empfehle ich jedoch die Verwendung einer materialisierten Ansicht (eine auf die Festplatte geschriebene Ansicht, die durch einen Trigger mit den übergeordneten Tabellen verknüpft ist). Die materialisierte Ansicht dient zum Speichern häufig gestellter, aber mühsam abzuleitender Daten und ist nützlich für eine hohe Anzahl von Schreibvorgängen und eine niedrige Anzahl von Lesevorgängen.

In einem Szenario mit hohem Schreib- und Leseaufwand sollten Sie eine Aufgabe im Hintergrund haben, die die Auswirkungen einer materialisierten Ansicht nachahmt, jedoch nicht in Echtzeit. Dies stellt einen "ausreichend guten" Durchschnitt dar, während die Schreib- und Leseleistung erhalten bleibt.

Unter keinen Umständen sollten Sie die abgeleitete Spalte wie eine "normale" Spalte behandeln: Stellen Sie sicher, dass die in der "Ansicht" der Widgets angezeigten Daten an anderer Stelle in der Tabelle vorhanden sind, sodass das gesamte Tupel durch alle von Ihnen ausgeführten Prozesse abgeleitet werden kann. Diese Frage ist auch stark datenbankspezifisch (und datenbankversionsspezifisch). Ich empfehle daher, die Leistung des Aggregats (mit geeigneten Indizes) anhand eines normal großen Datensatzes und der materialisierten Ansicht zu testen.

Brian Ballsun-Stanton
quelle
Ich fand diese Diskussion in Bezug auf materialisierte Ansichten sehr hilfreich. Es ist auf Oracle zugeschnitten, kann aber allgemein verstanden werden. Für diejenigen wie mich, die aus einem MySQL-Hintergrund stammen, unterscheidet sich eine MySQL-Ansicht von einer Materialized-Ansicht, sie ist virtuell und wird nicht auf Festplatte gespeichert (wie in dem von mir angegebenen Link beschrieben).
Siddhartha
upvoted! Ich wollte gerade die genaue Frage stellen, ich muss Indikatoren wie SMA, EMA, WMA, RSI usw. speichern und sie erfordern viel Rechenaufwand. Ich habe gerade eine Tabelle erstellt, die ich bisher manuell aktualisiert habe. Diese Indikatoren ändern sich jedes Mal um 100% Neue Daten kommen, was ist eine gute Strategie, um sie zu pflegen, ich weiß, Ansichten werden die Datenbank vollständig zerreißen, wenn jeder beginnt, die Ansichten links und rechts
abzufragen
11

Wie oft müssen Sie die Werte berechnen / anzeigen, um festzustellen, wie oft die zugrunde liegenden Zahlen geändert / aktualisiert werden.

Wenn Sie also eine Website mit 10.000 täglichen Treffern haben, die einen Wert anzeigt, der sich nur einmal pro Stunde ändert, würde ich ihn berechnen, wenn sich die zugrunde liegenden Werte ändern (was auch immer ein Datenbankauslöser sein könnte).

Wenn Sie ein Tool haben, mit dem Sie Statistiken anzeigen können, die sich im Sekundentakt ändern, aber nur drei Personen Zugriff haben und die nur ein paar Mal am Tag angezeigt werden, ist die Wahrscheinlichkeit höher, dass ich rechne es im laufenden Betrieb. (es sei denn, es dauert ein paar Minuten, um zu berechnen, dass es keine große Sache ist, veraltete Daten zu haben ... und mein Chef sagt mir, ich soll das Ding einfach jede Stunde aus cron generieren, also hat er es nicht abwarten, wann er es sich ansehen will.)

Joe
quelle
alle 15 Minuten 10 Metriken, die sich mit 1000 Zeilen pro Metrik zu 100% ändern
PirateApp
1
@PirateApp und wie oft wird es in einem durchschnittlichen 15-minütigen Fenster angezeigt? Was Sie auch tun können, ist, es auf erste Anfrage in einem 15-minütigen Fenster zu generieren und es dann für die Leute zwischenzuspeichern, die immer wieder nachladen
Joe,
Es wird auf einer Website sein, also nehme ich an, dass mindestens 10000 Leute es für den Anfang sehen werden, die Website ist nicht live, also haben Sie keine aktuellen Daten zum Nutzerverhalten
PirateApp
1
Das Problem ist, wie viele Anfragen im Verhältnis zu wie oft es sich ändert. Wenn Sie also etwas vorab generieren, das 10.000 Mal angezeigt wird, bevor sich die zugrunde liegenden Daten ändern, können Sie es vorab generieren. Wenn es nur einmal oder wenigermals angezeigt wird (weil sich die Daten so schnell ändern oder weil die Seite selten angezeigt wird), ist dies nicht der Fall.
Joe
4

Verwenden Sie die StaleWidgets-Tabelle als Warteschlange für "ungültige" (neu zu berechnende) Widgets. Verwenden Sie eine andere (asynchrone) Thread-Task, die diese Werte neu berechnen kann. Der Zeitraum oder Zeitpunkt der Neuberechnung hängt von den Systemanforderungen ab:

  • gerade gelesen,
  • am ende des monats,
  • für einige Benutzer zu Beginn des Tages
  • ...
Garik
quelle
1
Wie kommen sie dann in die abgestandene Warteschlange?
Jcolebrand
2
@jcolebrand ..im Moment des Einfügens / Löschens einer Bewertung (Bewertungstabelle) für ein Widget. In diesem Moment wird der Durchschnittswert in der Widgets-Tabelle ungültig, daher müssen wir in die Tabelle StaleWidgets einen Datensatz einfügen, der nur eine Spalte enthält - widget_id. Verwenden Sie einen Trigger oder einen gespeicherten Prozess, der einen Datensatz in die Bewertungstabelle oder natürlich in Ihre Variante einfügt.
Garik
2

Ich würde vorschlagen, on fly zu berechnen, wenn die Berechnung nicht zu umständlich ist und wenn Sie komplexe Berechnungen und häufige Aktualisierungen haben, aber nicht, dass die Frequenz gelesen wird, als Sie berechnete Daten speichern können und über eine zusätzliche Spalte (bool) verfügen, in der gespeichert wird, ob eine Neuberechnung erforderlich ist oder nicht . Setzen Sie diese Spalte beispielsweise auf true, wenn eine Neuberechnung durchgeführt werden soll, aber führen Sie keine Neuberechnung durch, und setzen Sie diese Spalte bei einer Neuberechnung auf false (dies stellt dar, dass der berechnete Wert aktuell und nicht veraltet ist).

Auf diese Weise müssen Sie nicht jedes Mal neu berechnen, sondern nur, wenn Sie den Spaltenwert lesen und neu berechnen müssen. Auf diese Weise sparen Sie viel Neuberechnung.

techExplorer
quelle
2

Insbesondere für den Fall gibt es eine andere Lösung, bei der Sie nicht alle Bewertungen addieren und durch die Summe dividieren müssen, um den Durchschnitt zu ermitteln. Stattdessen können Sie ein anderes Feld verwenden, das die Gesamtsumme der Bewertungen enthält. Wenn Sie also eine Bewertung hinzufügen, berechnen Sie den neuen Durchschnitt mit (avg_rating × total + new_rating) / total. Dies ist viel schneller als aggregiert und reduziert die Festplattenlesungen seit Ihnen Sie müssen nicht auf alle Bewertungswerte zugreifen. Ähnliche Lösungen können auch für andere Fälle gelten.

Der Nachteil dabei ist, dass es sich nicht um eine Säuretransaktion handelt, sodass Sie möglicherweise mit einem veralteten Rating abschließen. Sie können dies jedoch mithilfe von Triggern in der Datenbank lösen. Das andere Problem ist, dass die Datenbank nicht mehr normalisiert ist, aber keine Angst davor haben, Daten im Austausch mit der Leistung zu denormalisieren.

Adrian Martinez
quelle