Was passiert, wenn zwei Prozesse gleichzeitig versuchen, MATERIALISIERTE ANSICHT KONZURRENT ZU ERNEUERN?

13

Laut den Dokumenten:

KONZURRENT Aktualisieren Sie die materialisierte Ansicht, ohne gleichzeitige Auswahlen in der materialisierten Ansicht zu sperren. (...)

... ANDERE INHALTE ...

Selbst mit dieser Option kann jeweils nur ein REFRESH gegen eine materialisierte Ansicht ausgeführt werden .

Ich hatte eine Funktion, die die letzte Aktualisierungszeit für eine MATERIALISIERTE ANSICHT überprüfte, und wenn mehr als 60 Sekunden vergangen waren, würde sie aktualisiert.

Was würde jedoch passieren, wenn ich versuche, eine materialisierte Ansicht aus zwei getrennten Prozessen gleichzeitig zu aktualisieren? Würden sie sich anstellen oder einen Fehler auslösen?

Gibt es eine Möglichkeit zu erkennen, wann eine MATERIALISIERTE ANSICHT aktualisiert wird, und daher zu vermeiden, sie zu berühren?

Derzeit habe ich versucht, einen Tabellendatensatz zu füllen, bevor ich ihn aktualisiere ( refreshingauf true) und dann auf, falsewenn der Prozess abgeschlossen ist.

EXECUTE 'INSERT INTO refresh_status (last_update, refreshing) 
         VALUES (clock_timestamp(), true) RETURNING id') INTO refresh_id;
EXECUTE 'REFRESH MATERIALIZED VIEW CONCURRENTLY my_mat_view';
EXECUTE 'UPDATE refresh_status SET refreshing=false WHERE id=$1' USING refresh_id;

Wenn ich diese Prozedur aufrufe, überprüfe ich dann die aktuellste last_updateund ihren refreshingWert. Wenn dies refreshingzutrifft, versuchen Sie nicht, die materialisierte Ansicht zu aktualisieren.

EXECUTE 'SELECT 
           extract(epoch FROM now() - (last_update))::integer, 
           refreshing
         FROM refresh_status
         ORDER BY last_update DESC
         LIMIT 1' INTO update_seconds_ago, refreshing;

IF(updated_seconds_ago > 60 AND refreshing = FALSE) THEN
  -- the refresh block above
END IF;

Ich bin mir jedoch nicht sicher, ob das Aktualisierungsflag synchron aktualisiert wird (ich meine, es wartet wirklich darauf, dass die Aktualisierung tatsächlich abgeschlossen ist).

Ist dieser Ansatz rational oder fehlt mir hier etwas?

ffflabs
quelle

Antworten:

13

Wie in dieser Antwort erwähnt , " REFRESH MATERIALIZED VIEW CONCURRENTLYnimmt eine EXCLUSIVESperre" auf dem Tisch. Auf dem Weg zur Dokumentation können wir lesen, dass eine EXCLUSIVESperre für eine Tabelle "nur gleichzeitige ACCESS SHARESperren zulässt , dh nur Lesevorgänge aus der Tabelle können fortgesetzt werden". Im selben Absatz können wir sehen, dass " EXCLUSIVEKonflikte mit ... EXCLUSIVE", was bedeutet, dass eine andere REFRESH MATERIALIZED VIEW CONCURRENTLYAnweisung, die dieselbe EXCLUSIVESperre anfordert , warten muss, bis die frühere EXCLUSIVESperre aufgehoben wird.

Wenn Sie vermeiden möchten, einen undefinierten Zeitraum auf diese Sperre zu warten, können Sie die Sitzungsvariablelock_timeout auf einen sinnvollen Wert setzen.

mustaccio
quelle
PS: Halten Sie es für sinnvoll, diese Hilfstabelle beizubehalten, um gleichzeitigen (kein Wortspiel beabsichtigten) Versuchen mitzuteilen, dass MAT VIEW ausgelastet ist und daher in Ruhe gelassen werden sollte, auch wenn es den Anschein hat, dass eine Aktualisierung erforderlich ist?
Ffflabs
Es ist Ansichtssache; Wenn du denkst, dass es hilft, kannst du natürlich deine Logik behalten. Beachten Sie jedoch, dass Ihre Funktion den Rennbedingungen unterliegt und daher nicht 100% zuverlässig ist.
Mustaccio
Denken Sie, dass es sinnvoll ist, pg_locks zu überprüfen, um festzustellen, ob es einen gibt, der auf die Mattenansicht verweist?
Ffflabs
Auch hier ist die Rennbedingung möglich: Es besteht die Möglichkeit, dass eine Sperre zwischen Sie gesetzt wird, pg_locksum die Aktualisierung zu überprüfen und zu starten. Eine geeignete Methode zur Behebung von Sperrkonflikten besteht darin, ein Zeitlimit festzulegen und den Fehler zu behandeln.
Mustaccio
3

Wie von mustaccio festgestellt , überschneidet sich diese Frage erheblich mit Postgres Refresh Materialized View Locks .

Während die akzeptierte Antwort auf diese Frage einen Link enthält, der diese beantwortet, ist die Antwort auf diese Frage nicht direkt in dieser Antwort enthalten.

Also, um genau zu sein: Nach der PostgreSQL -Manpage auf explizite Sperren (Link ist auf die aktuelle Version Seite für PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYnimmt eine EXCLUSIVESperre. Die EXCLUSIVESperre scheint alle anderen Sperren zu blockieren, außer ACCESS SHARE - einschließlich anderer EXCLUSIVESperren.

Eine zweite REFRESH MATERIALIZED VIEW CONCURRENTLYAnforderung in derselben Ansicht wartet also darauf, dass die von der ersten erhaltene Sperre freigegeben wird.

RDFozz
quelle
Danke. Ich habe @ mustaccios Antwort immer noch als akzeptiert markiert, da er seinen Text bearbeitet hat, um meine Frage genauer zu beantworten.
Ffflabs
0

Dank der Antworten von mustaccio und RDFozz habe ich endlich verstanden, dass REFRESH ... CONCURRENTLYdie Verwendung einer exklusiven Sperre der Grund ist, aus dem die PostgreSQL-Dokumentation lautet :

Selbst mit dieser Option kann jeweils nur ein REFRESH gegen eine materialisierte Ansicht ausgeführt werden .

Ich befürchtete, dass dies bedeuten würde, dass jeder Versuch, eine gleichzeitige Aktualisierung durchzuführen, einen Fehler auslösen würde , aber angesichts ihrer Antworten gibt es keinen besonderen Fehler. Es ist nur eine Frage von Sperren, die gleichzeitige Versuche in die Warteschlange stellen. Die Dokumentation könnte also stattdessen wie folgt interpretiert werden:

Die während dieses Vorgangs erworbene Sperre verhindert andere Vorgänge als das Lesen aus der MATERIALISIERTEN ANSICHT. Weitere Versuche, die materialisierte Ansicht zu aktualisieren, während ein REFRESH ... CONCURRENTLY ausgeführt wird, stehen in der Warteschlange, bis die erste Sperre aufgehoben wird.

ffflabs
quelle