Co się stanie, jeśli dwa procesy spróbują ODŚWIEŻYĆ MATERIALIZOWANY WIDOK OBECNIE W tym samym czasie?

13

Według dokumentów:

OBECNIE Odśwież widok zmaterializowany bez blokowania współbieżnych zaznaczeń w widoku zmaterializowanym. (...)

... INNE TREŚCI ...

Nawet z tą opcją tylko jeden ODŚWIEŻANIE może działać jednocześnie z dowolnym zmaterializowanym widokiem .

I miał funkcję sprawdzenia ostatniego czasu odświeżania na zmaterializował widzenia, a jeśli więcej niż 60 sekund minęło, że będzie się ją odświeżyć.

Co by się jednak stało, gdybym spróbował odświeżyć zmaterializowany widok z dwóch oddzielnych procesów jednocześnie? czy staną w kolejce, czy zgłoszą błąd?

Czy istnieje sposób na wykrycie, kiedy WIDOK MATERIALIZOWANY jest odświeżany, i dlatego należy go unikać?

Obecnie postanowiłem wypełnić rekord tabeli przed odświeżeniem (ustawieniem refreshingna true), a następnie ustawieniem go na falsezakończenie procesu.

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;

Następnie za każdym razem, gdy wywołuję tę procedurę, sprawdzam najnowszą last_updatei jej refreshingwartość. Jeśli refreshingjest to prawda, nie próbuj odświeżać zmaterializowanego widoku.

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;

Nie jestem jednak pewien, czy flaga odświeżania jest aktualizowana synchronicznie (to znaczy naprawdę czeka na zakończenie odświeżania)

Czy to podejście jest racjonalne, czy coś mi brakuje?

ffflabs
źródło

Odpowiedzi:

13

Jak wspomniano w tej odpowiedzi , „ REFRESH MATERIALIZED VIEW CONCURRENTLYbierze EXCLUSIVEblokadę” na stole. Idąc śladem okruchów do dokumentacji , możemy przeczytać, że EXCLUSIVEblokada na stole „pozwala tylko na jednoczesne ACCESS SHAREblokady, tzn. Tylko odczyty z tabeli mogą być kontynuowane”. W tym samym akapicie widzimy, że „ EXCLUSIVEkoliduje z ... EXCLUSIVE”, co oznacza, że ​​inna REFRESH MATERIALIZED VIEW CONCURRENTLYinstrukcja, która żąda tej samej EXCLUSIVEblokady, będzie musiała poczekać, aż wcześniejsza EXCLUSIVEblokada zostanie zwolniona.

Jeśli chcesz uniknąć czekania na tę blokadę na czas nieokreślony, możesz ustawić zmienną sesjilock_timeout na rozsądną wartość.

mustaccio
źródło
PS: czy uważasz, że ma sens utrzymywanie tej tabeli pomocniczej w celu informowania o równoczesnych (nie zamierzonych słowach) próbach, że MAT VIEW jest zajęty i dlatego powinien zostać pozostawiony samemu sobie, nawet jeśli wydaje się, że wymaga odświeżenia?
ffflabs,
To kwestia opinii; jeśli uważasz, że to pomaga, możesz oczywiście zachować swoją logikę. Pamiętaj jednak, że twoja funkcja podlega warunkom wyścigowym i dlatego nie jest w 100% niezawodna.
mustaccio
Czy uważasz, że warto sprawdzić pg_locks, a następnie sprawdzić, czy istnieje odniesienie do widoku maty?
ffflabs,
Ponownie, możliwy stan wyścigu: istnieje szansa, że ​​między tobą zostanie umieszczona blokada, pg_locksa zaczniesz odświeżanie. Właściwym sposobem na rozwiązanie konfliktu blokady jest ustawienie limitu czasu i obsłużenie błędu.
mustaccio
3

Jak zauważył mustaccio , pytanie to pokrywa się znacznie z Postgres Refresh Materialized View Locks .

Jednak chociaż zaakceptowana odpowiedź na to pytanie zawiera link, który odpowiada na to pytanie, odpowiedź na to pytanie nie jest bezpośrednio zawarta w tym.

Tak, za szczególne: Zgodnie z ręcznym stronie PostgreSQL na wyraźną blokadą (Link jest do aktualnej wersji strony, dla PostgreSQL 10), REFRESH MATERIALIZED VIEW CONCURRENTLYzajmuje EXCLUSIVEzamek. EXCLUSIVEZamek wydaje się blokować wszystkie inne zamki z wyjątkiem ACCESS SHARE - który obejmuje inne EXCLUSIVEzamki.

Tak więc drugie REFRESH MATERIALIZED VIEW CONCURRENTLYżądanie w tym samym widoku będzie czekać na zwolnienie blokady uzyskanej przez pierwszą.

RDFozz
źródło
Dziękuję Ci. Nadal zaznaczyłem odpowiedź @ mustaccio jako zaakceptowaną, ponieważ zredagował swój tekst, aby był bardziej szczegółowy dla mojego pytania.
ffflabs,
0

Dzięki odpowiedziom Mustaccio i RDFozz w końcu zrozumiałem, że REFRESH ... CONCURRENTLYpodjęcie wyłącznej blokady jest powodem, dla którego dokumentacja PostgreSQL mówi :

Nawet z tą opcją tylko jeden ODŚWIEŻANIE może działać jednocześnie z dowolnym zmaterializowanym widokiem .

Obawiałem się, że oznacza to, że każda próba jednoczesnego odświeżenia spowoduje błąd , ale w świetle ich odpowiedzi nie ma żadnego specjalnego błędu. To tylko kwestia zamków, które będą kolejkować jednoczesne próby. Dokumentację można więc interpretować jako:

Blokada uzyskana podczas tej operacji zapobiegnie jakiejkolwiek operacji innej niż odczyt z WIDOKU MATERIALIZOWANEGO. Dalsze próby odświeżenia widoku zmaterializowanego podczas działania funkcji REFRESH ... CONCURRENTLY ustawią się w kolejce do momentu zwolnienia pierwszej blokady.

ffflabs
źródło