web-dev-qa-db-ja.com

2つのプロセスが同時にマテリアライズドビューを同時にリフレッシュしようとするとどうなりますか?

ドキュメントによると:

マテリアライズドビューの同時選択をロックアウトせずに、マテリアライズドビューを同時に更新します。 (...)

...その他のコンテンツ...

このオプションを使用しても、一度に実行できるREFRESHは1つだけです1つのマテリアライズドビュー

I had MATERIALIZED VIEWの最後の更新時間をチェックし、60秒以上経過した場合は更新する関数。

ただし、2つの別々のプロセスから同時にマテリアライズドビューを更新しようとするとどうなりますか?彼らはキューに入れますか、それともエラーを発生させますか?

MATERIALIZED VIEWが更新されていることを検出して、触れないようにする方法はありますか?

現在、更新する前にテーブルレコードにデータを入力して(refreshingtrueに設定して)、プロセスが終了したらそれを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がtrueの場合、マテリアライズドビューを更新しようとしないでください。

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
ffflabs

この答え で述べたように、テーブルで "REFRESH MATERIALIZED VIEW CONCURRENTLYEXCLUSIVEロックを取得します"。 documentation へのクラムトレイルに従って、テーブルのEXCLUSIVEロックは「同時ACCESS SHAREロックのみを許可します。つまり、テーブルからの読み取りのみが続行できます」と読み取ります。同じ段落で、「EXCLUSIVEは... EXCLUSIVEと競合します」ということがわかります。これは、同じEXCLUSIVEロックを要求する別のREFRESH MATERIALIZED VIEW CONCURRENTLYステートメントを意味します。以前のEXCLUSIVEロックが解放されるまで待つ必要があります。

未定義の期間、このロックを待たないようにする場合は、 セッション変数lock_timeout を適切な値に設定することができます。

13
mustaccio

mustaccio で述べたように、この質問は Postgres Refresh Materialized View Locks と大幅に重複しています。

ただし、その質問への 受け入れられた回答 にはこれに回答するリンクがありますが、この質問への回答は直接その質問に含まれていません。

具体的に言うと、明示的なロックに関する PostgreSQLマニュアルページ によると(PostGres 10の場合、リンクは現在のバージョンページにリンクされています)、REFRESH MATERIALIZED VIEW CONCURRENTLYEXCLUSIVEロックを取得します。 EXCLUSIVEロックは、他のすべてのロックをブロックしているように見えますexceptACCESS SHARE-他のEXCLUSIVEロックを含みます。

したがって、2番目のREFRESH MATERIALIZED VIEW CONCURRENTLY同じビューに対する要求は、最初のロックによって解放されるロックが取得されるのを待ちます。

3
RDFozz

mustaccio および RDFozz による回答のおかげで、私はようやくREFRESH ... CONCURRENTLY排他ロックを取ることが理由です PostgreSQLのドキュメントによると

このオプションを使用しても、一度に実行できるREFRESHは1つだけです1つのマテリアライズドビュー

これは、同時更新をしようとするとエラーがスローされることを意味していましたが、回答に照らして、特別なことはありませんエラーが発生しました。同時試行をエンキューするのは、ロックの問題です。したがって、ドキュメントは代わりに次のように解釈できます。

この操作中に取得されたロックは、MATERIALIZED VIEWからの読み取り以外の操作を防止します。 REFRESH ... CONCURRENTLYの実行中にマテリアライズドビューを更新しようとすると、最初のロックが解除されるまでキューに入れられます。

0
ffflabs