Cosa succede se due processi tentano di AGGIORNARE CON VISIONE CONTENUTO MATERIALIZZATO contemporaneamente?


13

Secondo i documenti:

CONCORRENTE Aggiorna la vista materializzata senza bloccare le selezioni simultanee sulla vista materializzata. (...)

... ALTRI CONTENUTI ...

Anche con questa opzione, solo un AGGIORNAMENTO alla volta può essere eseguito su una vista materializzata .

Ho avuto una funzione che verifica l'ultimo tempo di aggiornamento per una vista materializzata e, se più di 60 secondi erano passati, sarebbe per aggiornarlo.

Tuttavia, cosa accadrebbe se provassi ad aggiornare una vista materializzata da due processi separati contemporaneamente? si metterebbero in coda o genererebbero un errore?

C'è un modo per rilevare quando una VISUALIZZAZIONE MATERIALIZZATA viene aggiornata e quindi evitare di toccarla?

Attualmente, ho fatto ricorso per popolare un record di tabella prima di aggiornare (impostazione refreshingsu true) e quindi impostarlo su falsequando il processo è terminato.

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;

Quindi, ogni volta che chiamo questa procedura, controllo il più recente last_updatee il suo refreshingvalore. Se refreshingè vero, allora non provare ad aggiornare la vista materializzata.

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;

Tuttavia, non sono sicuro che il flag di aggiornamento venga aggiornato in modo sincrono (voglio dire, aspetta davvero che l'aggiornamento sia effettivamente completato)

Questo approccio è razionale o mi sto perdendo qualcosa qui?

Risposte:


13

Come menzionato in questa risposta , " REFRESH MATERIALIZED VIEW CONCURRENTLYprende un EXCLUSIVElucchetto" sul tavolo. Seguendo la scia di briciole fino alla documentazione possiamo leggere che un EXCLUSIVEblocco su una tabella "consente solo i ACCESS SHAREblocchi simultanei , vale a dire che solo le letture dalla tabella possono procedere". Nello stesso paragrafo possiamo vedere che "è in EXCLUSIVEconflitto con ... EXCLUSIVE", nel senso che un'altra REFRESH MATERIALIZED VIEW CONCURRENTLYistruzione, che richiede lo stesso EXCLUSIVEblocco, dovrà attendere fino al EXCLUSIVErilascio del blocco precedente .

Se si desidera evitare l'attesa di questo blocco per un periodo indefinito, è possibile impostare la variabile di sessionelock_timeout su un valore sensibile.


PS: pensi che abbia senso mantenere questa tabella ausiliaria per dire ai tentativi simultanei (non intesi giochi di parole) che MAT VIEW è occupato e quindi dovrebbe essere lasciato solo anche se sembra che abbia bisogno di un aggiornamento?
ffflabs,

È una questione di opinione; se pensi che ti aiuti, puoi ovviamente mantenere la tua logica. Nota, tuttavia, che la tua funzione è soggetta alle condizioni di gara e quindi non è affidabile al 100%.
Mustaccio

Pensi che sia fattibile controllare su pg_locks per vedere se ce n'è uno che fa riferimento alla vista del tappetino?
ffflabs,

Ancora una volta, le condizioni di gara sono possibili: c'è la possibilità che venga inserito un lucchetto tra il check pg_lockse l'avvio dell'aggiornamento. Un modo corretto per affrontare i conflitti di blocco è impostare il timeout e gestire l'errore.
Mustaccio,

3

Come notato da mustaccio , questa domanda si sovrappone in modo significativo con Postgres Refresh Materialized View Locks .

Tuttavia, mentre la risposta accettata a quella domanda ha un link che risponde a questa, la risposta a questa domanda non è direttamente inclusa in quella.

Quindi, per essere precisi: secondo la pagina di manuale PostgreSQL sul blocco esplicito (il collegamento è alla pagina della versione corrente, per PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYrichiede un EXCLUSIVEblocco. Il EXCLUSIVEblocco sembra bloccare tutti gli altri blocchi tranne ACCESS SHARE quello, inclusi gli altri EXCLUSIVEblocchi.

Quindi una seconda REFRESH MATERIALIZED VIEW CONCURRENTLYrichiesta nella stessa vista attenderà il rilascio del blocco ottenuto dal primo.


Grazie. Ho ancora contrassegnato la risposta di @ mustaccio come accettata da quando ha modificato il suo testo per essere più specifico alla mia domanda.
ffflabs,

0

Grazie alle risposte di mustaccio e RDFozz , ho finalmente capito che REFRESH ... CONCURRENTLYprendere un lucchetto esclusivo è il motivo per cui la documentazione di PostgreSQL dice :

Anche con questa opzione, solo un AGGIORNAMENTO alla volta può essere eseguito su una vista materializzata .

Avevo paura che questo significasse che qualsiasi tentativo di effettuare un aggiornamento simultaneo avrebbe generato un errore , ma alla luce delle loro risposte, non c'è alcun errore speciale. È solo una questione di blocchi che accorceranno i tentativi simultanei. Quindi la documentazione potrebbe invece essere interpretata come:

Il blocco acquisito durante questa operazione impedirà qualsiasi operazione diversa dalla lettura dalla VISTA MATERIALIZZATA. Ulteriori tentativi di aggiornamento della vista materializzata mentre è in esecuzione REFRESH ... CONCURRENTLY verranno messi in coda fino al rilascio del primo blocco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.