Que se passe-t-il si deux processus essaient de RAFRAÎCHIR LA VUE MATÉRIALISÉE DE MANIÈRE CONCURRENTE en même temps?


13

Selon les documents:

CONCURRENTLY Actualisez la vue matérialisée sans verrouiller les sélections simultanées sur la vue matérialisée. (...)

... AUTRES CONTENUS ...

Même avec cette option, un seul REFRESH à la fois peut s'exécuter sur une seule vue matérialisée .

J'eu une fonction qui a vérifié la dernière fois de rafraîchissement pour une vue et, si MATERIALIZED plus de 60 secondes se sont écoulées, il le rafraîchir.

Cependant, que se passerait-il si j'essayais d'actualiser une vue matérialisée à partir de deux processus distincts en même temps? feraient-ils la queue ou soulèveraient-ils une erreur?

Existe-t-il un moyen de détecter quand une VUE MATÉRIALISÉE est en cours de rafraîchissement et donc d'éviter de la toucher?

Actuellement, j'ai recouru à remplir un enregistrement de table avant d'actualiser (en définissant refreshingsur true) puis de le définir à la falsefin du processus.

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;

Ensuite, chaque fois que j'appelle cette procédure, je vérifie la plus récente last_updateet sa refreshingvaleur. Si refreshingc'est vrai, n'essayez pas de rafraîchir la vue matérialisée.

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;

Cependant, je ne suis pas sûr que l'indicateur d'actualisation soit mis à jour de manière synchrone (je veux dire, il attend vraiment que le rafraîchissement soit réellement terminé)

Cette approche est-elle rationnelle ou manque-t-il quelque chose ici?

Réponses:


13

Comme mentionné dans cette réponse , " REFRESH MATERIALIZED VIEW CONCURRENTLYprend un EXCLUSIVEverrou" sur la table. En suivant le chemin d'accès à la documentation, nous pouvons lire qu'un EXCLUSIVEverrou sur une table "autorise uniquement les ACCESS SHAREverrous simultanés , c'est-à-dire que seules les lectures de la table peuvent se poursuivre". Dans le même paragraphe, nous pouvons voir que "entre en EXCLUSIVEconflit avec ... EXCLUSIVE", ce qui signifie qu'une autre REFRESH MATERIALIZED VIEW CONCURRENTLYinstruction, qui demande le même EXCLUSIVEverrou, devra attendre que le EXCLUSIVEverrou précédent soit libéré.

Si vous souhaitez éviter d'attendre ce verrou pendant une période indéfinie, vous pouvez définir la variable de sessionlock_timeout sur une valeur sensible.


PS: pensez-vous qu'il est logique de conserver cette table auxiliaire pour indiquer aux tentatives simultanées (sans jeu de mots) que MAT VIEW est occupé et doit donc être laissé seul même s'il semble qu'il ait besoin d'un rafraîchissement?
ffflabs

C'est une question d'opinion; si vous pensez que cela vous aide, vous pouvez bien sûr garder votre logique. Notez cependant que votre fonction est soumise aux conditions de course et n'est donc pas fiable à 100%.
mustaccio

Pensez-vous qu'il est viable de vérifier pg_locks puis de voir s'il y en a un qui fait référence à la vue du tapis?
ffflabs

Encore une fois, la condition de course est possible: il y a une chance qu'un verrou soit placé entre vous vérifiez pg_lockset commencez votre rafraîchissement. Un moyen approprié pour résoudre les conflits de verrouillage consiste à définir le délai d'expiration et à gérer l'erreur.
mustaccio

3

Comme l'a noté mustaccio , cette question chevauche considérablement les verrous de vue matérialisée Postgres Refresh .

Cependant, alors que la réponse acceptée à cette question a un lien qui répond à celle-ci, la réponse à cette question n'est pas directement incluse dans celle-ci.

Donc, pour être précis: selon la page de manuel de PostgreSQL sur le verrouillage explicite (le lien est vers la page de la version actuelle, pour PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYprend un EXCLUSIVEverrou. Le EXCLUSIVEverrou semble bloquer tous les autres verrous sauf ACCESS SHARE - cela inclut les autres EXCLUSIVEverrous.

Une seconde REFRESH MATERIALIZED VIEW CONCURRENTLYrequête sur la même vue attendra donc que le verrou obtenu par la première soit libéré.


Je vous remercie. J'ai toujours marqué la réponse de @ mustaccio comme acceptée car il a édité son texte pour être plus spécifique à ma question.
ffflabs

0

Grâce aux réponses de mustaccio et RDFozz , j'ai finalement compris que la REFRESH ... CONCURRENTLYprise d'un verrou exclusif est la raison pour laquelle la documentation PostgreSQL dit :

Même avec cette option, un seul REFRESH à la fois peut s'exécuter sur une seule vue matérialisée .

J'avais peur que cela signifie que toute tentative de rafraîchissement simultané entraînerait une erreur , mais à la lumière de leurs réponses, aucune erreur particulière n'est impliquée. C'est juste une question de verrous qui mettront en file d'attente les tentatives simultanées. Ainsi, la documentation pourrait plutôt être interprétée comme:

Le verrou acquis au cours de cette opération empêchera toute opération autre que la lecture de la VUE MATÉRIALISÉE. D'autres tentatives d'actualisation de la vue matérialisée pendant l'exécution de REFRESH ... CONCURRENTLY feront la queue jusqu'à ce que le premier verrou soit libéré.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.