In regelmäßigen Abständen werden neue Werte hinzugefügt graphoder ein vorhandener Wert aktualisiert. Ich möchte die Ansicht graph_avgalle paar Stunden nur für die aktualisierten Werte aktualisieren. In PostgreSQL 9.3 wird jedoch die gesamte Tabelle aktualisiert. Das ist ziemlich zeitaufwändig. Die nächste Version 9.4 ermöglicht ein CONCURRENTUpdate, aktualisiert jedoch weiterhin die gesamte Ansicht. Bei Hunderten von Millionen Zeilen dauert dies einige Minuten.
Was ist ein guter Weg, um den Überblick über aktualisierte und neue Werte zu behalten und die Ansicht nur teilweise zu aktualisieren?
Sie können jederzeit eine eigene Tabelle implementieren, die als "materialisierte Ansicht" dient. Das mussten Sie tun, bevor MATERIALIZED VIEWPostgres 9.3 so oder so implementiert wurde.
Beispielsweise können Sie eine Ebene erstellen VIEW:
CREATEVIEW graph_avg_view ASSELECT xaxis, AVG(value)AS avg_val
FROM graph
GROUPBY xaxis;
Und materialisieren Sie das Ergebnis als Ganzes einmal oder wann immer Sie von vorne anfangen müssen:
(Oder die Verwendung SELECTAnweisung direkt, ohne ein zu schaffen VIEW.)
Dann, abhängig von undisclosed Details Ihrer Verwendung Fall, könnten Sie DELETE/ UPDATE/ INSERTÄnderungen manuell.
Eine grundlegende DML-Anweisung mit datenmodifizierenden CTEs für Ihre Tabelle wie folgt :
Unter der Annahme , sonst niemand versucht zu schreiben , um graph_avggleichzeitig (Lesen ist kein Problem):
WITH del AS(DELETEFROM graph_avg t
WHERENOTEXISTS(SELECT1FROM graph_avg_view v WHERE v.xaxis = v.xaxis);), upd AS(UPDATE graph_avg t
FROM graph_avg_view v
WHERE t.xaxis = v.xaxis
AND t.avg_val <> v.avg_val
)INSERTINTO graph_avg t
SELECT*FROM graph_avg_view v
LEFTJOIN graph_avg t USING(xaxis)WHERE t.xaxis ISNULL;
Dies sollte aber höchstwahrscheinlich optimiert werden.
Grundrezept:
Fügen Sie Ihrer Basistabelle eine timestampStandardspalte hinzu now(). Nennen wir es ts.
Wenn Sie Aktualisierungen haben, fügen Sie einen Auslöser hinzu, um den aktuellen Zeitstempel für jede Aktualisierung festzulegen, die entweder xaxisoder geändert wird value.
Erstellen Sie eine winzige Tabelle, um sich den Zeitstempel Ihres letzten Schnappschusses zu merken. Nennen wir es mv:
CREATETABLE mv (
tbl text PRIMARYKEY, ts timestamp NOTNULLDEFAULT'-infinity');-- possibly more details
Erstellen Sie diesen mehrspaltigen Teilindex:
CREATEINDEX graph_mv_latest ON graph (xaxis, value)WHERE ts >='-infinity';
Verwenden Sie den Zeitstempel des letzten Snapshots als Vergleichselement in Ihren Abfragen, um den Snapshot mit perfekter Indexnutzung zu aktualisieren.
Löschen Sie am Ende der Transaktion den Index und erstellen Sie ihn neu, wobei der Transaktionszeitstempel den Zeitstempel im Indexprädikat (anfangs '-infinity') ersetzt, den Sie auch in Ihrer Tabelle speichern. Alles in einer Transaktion.
Beachten Sie, dass der Teilindex Abdeckung ist groß INSERTund UPDATEOperationen, aber nicht DELETE. Um dies abzudecken, müssen Sie die gesamte Tabelle betrachten. Alles hängt von den genauen Anforderungen ab.
Vielen Dank für die Klarheit in Bezug auf materialisierte Ansichten und den Vorschlag einer alternativen Antwort.
user4150760
13
Gleichzeitiges Update (Postgres 9.4)
Postgres 9.4 ist zwar kein inkrementelles Update, wie Sie es gewünscht haben, bietet jedoch eine neue Funktion für gleichzeitige Updates .
Um das Dokument zu zitieren ...
Vor PostgreSQL 9.4 bedeutete das Aktualisieren einer materialisierten Ansicht das Sperren der gesamten Tabelle und damit das Verhindern von Abfragen. Wenn eine Aktualisierung lange Zeit in Anspruch nahm, um die exklusive Sperre zu erhalten (während sie auf Abfragen wartet, die sie zum Beenden verwenden), wurde sie der Reihe nach gesperrt hält nachfolgende Abfragen auf. Dies kann jetzt mit dem Schlüsselwort CONCURRENTLY gemildert werden:
Für die materialisierte Ansicht muss jedoch ein eindeutiger Index vorhanden sein. Anstatt die materialisierte Ansicht zu sperren, wird stattdessen eine temporär aktualisierte Version davon erstellt, die beiden Versionen verglichen und dann INSERTs und DELETEs mit der materialisierten Ansicht verglichen, um den Unterschied anzuwenden. Dies bedeutet, dass Abfragen die materialisierte Ansicht weiterhin verwenden können, während sie aktualisiert wird. Im Gegensatz zu seiner nicht gleichzeitigen Form werden Tupel nicht eingefroren, und es muss aufgrund der oben genannten DELETEs VAKUUMIERT werden, wodurch tote Tupel zurückbleiben.
Dieses gleichzeitige Update führt noch eine vollständige neue Abfrage durch (nicht inkrementell). CONCURRENTLY spart also nicht die gesamte Rechenzeit, sondern minimiert nur die Zeit, die Ihre materialisierte Ansicht für die Verwendung während der Aktualisierung nicht verfügbar ist.
Für einen Moment war ich aufgeregt, bis ich genau las. it instead creates a temporary updated version of it...compares the two versions- Dies bedeutet, dass die temporär aktualisierte Version immer noch eine vollständige Berechnung ist und dann den Unterschied auf die vorhandene Ansicht anwendet. Im Grunde genommen mache ich immer noch ALLE Berechnungen neu, aber nur in der temporären Tabelle.
user4150760
5
Allerdings CONCURRENTLYspart dies nicht die gesamte Rechenzeit, sondern minimiert nur die Zeit, die Ihre materialisierte Ansicht für die Verwendung während der Aktualisierung nicht verfügbar ist.
Gleichzeitiges Update (Postgres 9.4)
Postgres 9.4 ist zwar kein inkrementelles Update, wie Sie es gewünscht haben, bietet jedoch eine neue Funktion für gleichzeitige Updates .
Um das Dokument zu zitieren ...
Dieses gleichzeitige Update führt noch eine vollständige neue Abfrage durch (nicht inkrementell). CONCURRENTLY spart also nicht die gesamte Rechenzeit, sondern minimiert nur die Zeit, die Ihre materialisierte Ansicht für die Verwendung während der Aktualisierung nicht verfügbar ist.
quelle
it instead creates a temporary updated version of it...compares the two versions
- Dies bedeutet, dass die temporär aktualisierte Version immer noch eine vollständige Berechnung ist und dann den Unterschied auf die vorhandene Ansicht anwendet. Im Grunde genommen mache ich immer noch ALLE Berechnungen neu, aber nur in der temporären Tabelle.CONCURRENTLY
spart dies nicht die gesamte Rechenzeit, sondern minimiert nur die Zeit, die Ihre materialisierte Ansicht für die Verwendung während der Aktualisierung nicht verfügbar ist.