Що станеться, якщо два процеси спробують ПОТРІБНО МАТЕРІАЛІЗОВАНИЙ ПОГЛЯД одночасно?


13

Згідно з документами:

СУЧАСНО Оновіть матеріалізований вигляд, не вимикаючи паралельно вибрані в матеріалізованому поданні. (...)

... ІНШІ ЗМІСТ ...

Навіть при такому варіанті лише один ПОВТОРЕННЯ одночасно може протистояти будь-якому матеріалізованому виду .

У мене була функція, яка перевіряла час останнього оновлення на МАТЕРІАЛІЗОВАНИЙ ВИДІЛ, і якщо минуло б більше 60 секунд, оновило б його.

Однак, що буде, якщо я спробую оновити матеріалізований погляд з двох окремих процесів одночасно? вони б стояли в черзі чи вони піднімуть помилку?

Чи є спосіб виявити, коли МАТЕРІАЛІЗОВАНИЙ ВИДІЛЬ оновлюється, і тому уникати його торкання?

В даний час я вдавався , щоб заповнити запис таблиці перед оновленням (настройка refreshingв true) , а потім встановити його в , falseколи процес завершено.

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;

Потім, коли я називаю цю процедуру, я перевіряю найсвіжішу last_updateта її refreshingзначення. Якщо refreshingце правда, то не намагайтеся оновити вигляд, що матеріалізується.

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;

Однак я не впевнений, що освіжаючий прапор оновлюється синхронно (я маю на увазі, він дійсно чекає, коли оновлення дійсно буде повним)

Цей підхід раціональний чи я щось тут пропускаю?

Відповіді:


13

Як згадується у цій відповіді , « REFRESH MATERIALIZED VIEW CONCURRENTLYбере EXCLUSIVEзамок» на столі. Послідуючи крихту документації, ми можемо прочитати, що EXCLUSIVEблокування на столі "допускає лише одночасні ACCESS SHAREблокування, тобто можна читати лише з таблиці". У цьому ж абзаці ми можемо побачити, що " EXCLUSIVEконфліктує з ... EXCLUSIVE", тобто інше REFRESH MATERIALIZED VIEW CONCURRENTLYтвердження, яке вимагає того ж EXCLUSIVEблокування, доведеться почекати, поки не EXCLUSIVEбуде звільнено попереднє блокування.

Якщо ви не хочете чекати цього блокування протягом невизначеного періоду, ви можете встановити змінну сеансуlock_timeout на значуще значення.


PS: Ви вважаєте, чи є сенс тримати цю допоміжну таблицю, щоб повідомити про одночасні (не призначені для каламбуру) спроби, що MAT VIEW зайнятий, і тому його слід залишити в спокої, навіть якщо здається, що воно потребує оновлення?
ffflabs

Це питання думки; якщо ви думаєте, що це допомагає, звичайно, ви можете зберегти свою логіку. Однак зауважте, що ваша функція залежить від перегонових умов і тому не є на 100% надійною.
мустаччо

Ви вважаєте, що цілком можливо перевірити pg_locks, щоб побачити, чи є один із посилань на матовий вигляд?
ffflabs

Знову ж, можливий стан гонки: є ймовірність, що між вами буде встановлено замок pg_locksі почнете оновлення. Правильний спосіб вирішення конфліктів блокування - встановити тайм-аут та вирішити помилку.
мустаччо

3

Як зауважив мустаччо , це питання суттєво перегукується із блоками Postgres Refresh Materialized View Locks .

Однак, хоча у прийнятій відповіді на це питання є посилання, яке відповідає на це, відповідь на це питання безпосередньо не входить до цього.

Отже, щоб бути конкретним: Відповідно до сторінки посібника PostgreSQL щодо явного блокування (Посилання на сторінку поточної версії, для PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYвідбувається EXCLUSIVEблокування. EXCLUSIVEЗамок , здається, блокує всі інші замки , за винятком ACCESS SHARE - що включає в себе інші EXCLUSIVEзамки.

Отже, другий REFRESH MATERIALIZED VIEW CONCURRENTLYзапит того ж виду буде чекати, коли замок, отриманий першим, буде звільнений.


Дякую. Я все-таки позначив відповідь @ mustaccio як прийняту, оскільки він редагував свій текст, щоб бути більш конкретним до мого питання.
ffflabs

0

Завдяки відповідям mustaccio та RDFozz я нарешті зрозумів, що REFRESH ... CONCURRENTLYзняття ексклюзивного блокування є причиною, в якій документація PostgreSQL говорить :

Навіть при такому варіанті лише один ПОВТОРЕННЯ одночасно може протистояти будь-якому матеріалізованому виду .

Я побоювався, що це означає, що будь-яка спроба одночасного оновлення призведе до помилки , але, зважаючи на їх відповіді, особливих помилок не було. Це лише питання замків, які спричинять одночасні спроби. Таким чином, документація може бути інтерпретована як:

Замок, придбаний під час цієї операції, запобігає будь-якій операції, окрім читання з МАТЕРІАЛІЗОВАНОГО ОГЛЯД. Подальші спроби оновити Матеріалізований вигляд під час запуску ПОТРІБНОГО ... КОНЦУРЕНТНО буде стояти в черзі до першого звільнення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.