it-swarm.com.de

Aktualisieren Sie eine materialisierte Ansicht automatisch mithilfe einer Regel oder einer Benachrichtigung

Ich habe eine materialisierte Sicht auf eine PostgreSQL 9.3-Datenbank, die sich selten ändert (ungefähr zweimal am Tag). In diesem Fall möchte ich die Daten jedoch umgehend aktualisieren.

Hier ist, worüber ich bisher nachgedacht habe:

Es gibt eine materialisierte Ansicht mat_view, Die ihre Daten mithilfe einer Join-Anweisung aus den Tabellen table1 Und table2 Bezieht.

Immer wenn sich etwas in table1 Oder table2 Ändert, habe ich bereits einen Trigger, der eine kleine Konfigurationstabelle config aktualisiert, bestehend aus

table_name | mat_view_name | need_update
-----------+---------------+------------
table1     | mat_view      | TRUE/FALSE
table2     | mat_view      | TRUE/FALSE

Wenn sich also etwas in table1 Ändert (es gibt einen Auslöser für UPDATE und für DELETE für jede Anweisung), wird das Feld need_update In der ersten Zeile auf TRUE gesetzt. Gleiches gilt für table2 Und die zweite Zeile.

Wenn need_update TRUE ist, muss die materialisierte Ansicht natürlich aktualisiert werden.

UPDATE : Da materialisierte Ansichten keine Regeln unterstützen (wie in einem Kommentar unten unter @pozs erwähnt), würde ich noch einen Schritt weiter gehen. Ich würde eine Dummy-Ansicht v_mat_view Mit der Definition "SELECT * FROM mat_view" Erstellen. Wenn der Benutzer in dieser Ansicht ein SELECT ausführt, muss ich eine Regel für SELECT erstellen, die Folgendes ausführt:

  • überprüfen Sie, ob mat_view aktualisiert werden soll (SELECT 1 FROM config WHERE mat_view_name='mat_view' AND need_update=TRUE)
  • setze das need_update Flag mit UPDATE config SET need_update=FALSE where mat_view_name='mat_view' zurück
  • REFRESH MATERIALIZED VIEW mat_view
  • und zuletzt die ursprüngliche SELECT-Anweisung ausführen, jedoch mit mat_view als Ziel.

PDATE2: Ich habe versucht, die obigen Schritte zu erstellen:

Erstellen Sie eine Funktion, die die vier oben genannten Punkte behandelt:

CREATE OR REPLACE FUNCTION mat_view_selector()
RETURNS SETOF mat_view AS $body$
BEGIN
  -- here is checking whether to refresh the mat_view
  -- then return the select:
  RETURN QUERY SELECT * FROM mat_view;
END;
$body$ LANGUAGE plpgsql;

Erstellen Sie die Ansicht v_mat_view, Die wirklich aus der Funktion mat_view_selector Auswählt:

CREATE TABLE v_mat_view AS SELECT * from mat_view LIMIT 1;
DELETE FROM v_mat_view;

CREATE RULE "_RETURN" AS
    ON SELECT TO v_mat_view
    DO INSTEAD 
        SELECT * FROM mat_view_selector();
    -- this also converts the empty table 'v_mat_view' into a view.

Das Ergebnis ist unbefriedigend:

# explain analyze select field1 from v_mat_view where field2 = 44;
QUERY PLAN
Function Scan on mat_view_selector (cost=0.25..12.75 rows=5 width=4)
(actual time=15.457..18.048 rows=1 loops=1)
Filter: (field2 = 44)
Rows Removed by Filter: 20021
Total runtime: 31.753 ms

im vergleich zur auswahl aus der mat_view selbst:

# explain analyze select field1 from mat_view where field2 = 44;
QUERY PLAN
Index Scan using mat_view_field2 on mat_view (cost=0.29..8.30 rows=1 width=4)
  (actual time=0.015..0.016 rows=1 loops=1)
Index Cond: (field2 = 44)
Total runtime: 0.036 ms

Im Grunde funktioniert es also, aber die Leistung könnte ein Problem sein.

Hat jemand bessere Ideen? Wenn nicht, dann müsste ich es irgendwie in die Anwendungslogik implementieren oder schlimmer: einen einfachen Cronjob ausführen, der jede Minute oder so läuft. :-(

59
mawimawi

PostgreSQL 9.4 hinzugefügt REFRESH CONCURRENTLY zu Materialized Views.

Dies ist möglicherweise genau das, wonach Sie suchen, wenn Sie versuchen, eine asynchrone Aktualisierung der materialisierten Ansicht einzurichten.

Benutzer, die aus der materialisierten Ansicht auswählen, sehen falsche Daten, bis die Aktualisierung abgeschlossen ist. In vielen Szenarien, in denen eine materialisierte Ansicht verwendet wird, ist dies jedoch ein akzeptabler Kompromiss.

Verwenden Sie einen Auslöser auf Anweisungsebene, der die zugrunde liegenden Tabellen auf Änderungen überwacht und die materialisierte Ansicht gleichzeitig aktualisiert.

25
Jeff Widman

Sie sollten die Ansicht in Triggern nach dem Einfügen/Aktualisieren/Löschen/Abschneiden für jede Anweisung in table1 Und table2 Aktualisieren.

create or replace function refresh_mat_view()
returns trigger language plpgsql
as $$
begin
    refresh materialized view mat_view;
    return null;
end $$;

create trigger refresh_mat_view
after insert or update or delete or truncate
on table1 for each statement 
execute procedure refresh_mat_view();

create trigger refresh_mat_view
after insert or update or delete or truncate
on table2 for each statement 
execute procedure refresh_mat_view();

Auf diese Weise ist Ihre materialisierte Ansicht immer auf dem neuesten Stand. Diese einfache Lösung ist mit häufigen Einfügungen/Aktualisierungen und sporadischen Auswahlen möglicherweise schwer zu akzeptieren. In Ihrem Fall (ändert sich selten etwa zweimal am Tag) passt es sich ideal Ihren Bedürfnissen an.


Um verzögerte Aktualisierung einer materialisierten Ansicht zu realisieren, benötigen Sie eine der folgenden Funktionen:

  • asynchroner Trigger
  • vor Auswahl auslösen
  • regel auf vorher auswählen

Postgres hat keine von ihnen, es scheint also keine klare Postgres-Lösung zu geben.

In Anbetracht dessen würde ich eine Wrapper-Funktion für Selects in mat_view in Betracht ziehen, z.

CREATE OR REPLACE FUNCTION select_from_mat_view(where_clause text)
RETURNS SETOF mat_view AS $body$
BEGIN
  -- here is checking whether to refresh the mat_view
  -- then return the select:
  RETURN QUERY EXECUTE FORMAT ('SELECT * FROM mat_view %s', where_clause);
END;
$body$ LANGUAGE plpgsql;

Ob es in der Praxis akzeptabel ist, hängt von Einzelheiten ab, die ich nicht kenne.

103
klin