¿Qué sucede si dos procesos intentan ACTUALIZAR LA VISTA MATERIALIZADA CONCURRENTEMENTE al mismo tiempo?


13

Según los documentos:

CONCURRENTEMENTE Actualizar la vista materializada sin bloquear selecciones concurrentes en la vista materializada. (...)

... OTROS CONTENIDOS ...

Incluso con esta opción, solo un REFRESH a la vez puede ejecutarse contra cualquier vista materializada .

Yo tenía una función que comprueba el último tiempo de actualización de una vista materializada y, si habían pasado más de 60 segundos, sería para actualizarlo.

Sin embargo, ¿qué sucedería si trato de actualizar una vista materializada de dos procesos separados al mismo tiempo? ¿harían cola o generarían un error?

¿Hay alguna forma de detectar cuándo se actualiza una VISTA MATERIALIZADA y, por lo tanto, evitar tocarla?

Actualmente, he recurrido a rellenar un registro de tabla antes de actualizar (establecer refreshingen true) y luego configurarlo falsecuando el proceso haya finalizado.

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;

Luego, cada vez que llamo a este procedimiento, verifico el más reciente last_updatey su refreshingvalor. Si refreshinges cierto, no intente actualizar la vista materializada.

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;

Sin embargo, no estoy seguro de que el indicador de actualización se actualice sincrónicamente (es decir, realmente espera a que la actualización se complete)

¿Es este enfoque racional o me falta algo aquí?

Respuestas:


13

Como se menciona en esta respuesta , " REFRESH MATERIALIZED VIEW CONCURRENTLYtoma un EXCLUSIVEcandado" sobre la mesa. Siguiendo el rastro de migajas a la documentación , podemos leer que un EXCLUSIVEbloqueo en una tabla "solo permite ACCESS SHAREbloqueos concurrentes , es decir, solo las lecturas de la tabla pueden continuar". En el mismo párrafo podemos ver que " EXCLUSIVEentra en conflicto con ... EXCLUSIVE", lo que significa que otra REFRESH MATERIALIZED VIEW CONCURRENTLYdeclaración, que solicita el mismo EXCLUSIVEbloqueo, tendrá que esperar hasta que EXCLUSIVEse libere el bloqueo anterior .

Si desea evitar esperar este bloqueo durante un período indefinido, puede establecer la variable de sesiónlock_timeout en un valor razonable.


PD: ¿cree que tiene sentido mantener esta tabla auxiliar para indicar intentos concurrentes (sin juego de palabras) de que MAT VIEW está ocupado y, por lo tanto, debe dejarse solo, incluso si parece que necesita una actualización?
ffflabs

Es una cuestión de opinión; si crees que te ayuda, por supuesto, puedes mantener tu lógica. Tenga en cuenta, sin embargo, que su función está sujeta a condiciones de carrera y, por lo tanto, no es 100% confiable.
mustaccio

¿Crees que es viable verificar pg_locks para ver si hay alguna que haga referencia a la vista del tapete?
ffflabs

Una vez más, la condición de carrera es posible: existe la posibilidad de que se coloque un bloqueo entre el control pg_locksy el inicio de la actualización. Una forma adecuada de abordar los conflictos de bloqueo es establecer el tiempo de espera y manejar el error.
mustaccio

3

Como señaló Mustaccio , esta pregunta se superpone significativamente con los bloqueos de vista materializada de actualización de Postgres .

Sin embargo, aunque la respuesta aceptada a esa pregunta tiene un enlace que responde a esta, la respuesta a esta pregunta no se incluye directamente en esa.

Entonces, para ser específicos: de acuerdo con la página del manual de PostgreSQL sobre bloqueo explícito (el enlace es a la página de la versión actual, para PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYse EXCLUSIVEbloquea. El EXCLUSIVEbloqueo parece bloquear todos los demás bloqueos, excepto ACCESS SHARE que incluye otros EXCLUSIVEbloqueos.

Por lo tanto, una segunda REFRESH MATERIALIZED VIEW CONCURRENTLYsolicitud en la misma vista esperará a que se libere el bloqueo obtenido por el primero.


Gracias. Todavía marqué la respuesta de @ mustaccio como aceptada ya que editó su texto para ser más específico a mi pregunta.
ffflabs

0

Gracias a las respuestas de mustaccio y RDFozz , finalmente entendí que REFRESH ... CONCURRENTLYtomar un bloqueo exclusivo es la razón por la cual la documentación de PostgreSQL dice :

Incluso con esta opción, solo un REFRESH a la vez puede ejecutarse contra cualquier vista materializada .

Tenía miedo de que esto significara que cualquier intento de hacer una actualización simultánea arrojaría un error , pero a la luz de sus respuestas, no hay ningún error especial involucrado. Es solo una cuestión de cerraduras que provocarán intentos simultáneos. Por lo tanto, la documentación podría interpretarse como:

El bloqueo adquirido durante esta operación evitará cualquier otra operación que no sea la lectura desde la VISTA MATERIALIZADA. Los intentos adicionales de actualizar la vista materializada mientras se ejecuta una actualización ... CONCURRENTEMENTE se colocará en cola hasta que se libere el primer bloqueo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.