ドキュメントによると:
マテリアライズドビューの同時選択をロックアウトせずに、マテリアライズドビューを同時に更新します。 (...)
...その他のコンテンツ...
このオプションを使用しても、一度に実行できるREFRESHは1つだけです1つのマテリアライズドビュー。
I had MATERIALIZED VIEWの最後の更新時間をチェックし、60秒以上経過した場合は更新する関数。
ただし、2つの別々のプロセスから同時にマテリアライズドビューを更新しようとするとどうなりますか?彼らはキューに入れますか、それともエラーを発生させますか?
MATERIALIZED VIEWが更新されていることを検出して、触れないようにする方法はありますか?
現在、更新する前にテーブルレコードにデータを入力して(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
が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;
ただし、更新フラグが同期的に更新されているかどうかはわかりません(つまり、更新が実際に完了するまで実際に待機しています)。
このアプローチは合理的ですか、ここで何か不足していますか?
この答え で述べたように、テーブルで "REFRESH MATERIALIZED VIEW CONCURRENTLY
はEXCLUSIVE
ロックを取得します"。 documentation へのクラムトレイルに従って、テーブルのEXCLUSIVE
ロックは「同時ACCESS SHARE
ロックのみを許可します。つまり、テーブルからの読み取りのみが続行できます」と読み取ります。同じ段落で、「EXCLUSIVE
は... EXCLUSIVE
と競合します」ということがわかります。これは、同じEXCLUSIVE
ロックを要求する別のREFRESH MATERIALIZED VIEW CONCURRENTLY
ステートメントを意味します。以前のEXCLUSIVE
ロックが解放されるまで待つ必要があります。
未定義の期間、このロックを待たないようにする場合は、 セッション変数lock_timeout
を適切な値に設定することができます。
mustaccio で述べたように、この質問は Postgres Refresh Materialized View Locks と大幅に重複しています。
ただし、その質問への 受け入れられた回答 にはこれに回答するリンクがありますが、この質問への回答は直接その質問に含まれていません。
具体的に言うと、明示的なロックに関する PostgreSQLマニュアルページ によると(PostGres 10の場合、リンクは現在のバージョンページにリンクされています)、REFRESH MATERIALIZED VIEW CONCURRENTLY
はEXCLUSIVE
ロックを取得します。 EXCLUSIVE
ロックは、他のすべてのロックをブロックしているように見えますexceptACCESS SHARE
-他のEXCLUSIVE
ロックを含みます。
したがって、2番目のREFRESH MATERIALIZED VIEW CONCURRENTLY
同じビューに対する要求は、最初のロックによって解放されるロックが取得されるのを待ちます。
mustaccio および RDFozz による回答のおかげで、私はようやくREFRESH ... CONCURRENTLY
排他ロックを取ることが理由です PostgreSQLのドキュメントによると :
このオプションを使用しても、一度に実行できるREFRESHは1つだけです1つのマテリアライズドビュー。
これは、同時更新をしようとするとエラーがスローされることを意味していましたが、回答に照らして、特別なことはありませんエラーが発生しました。同時試行をエンキューするのは、ロックの問題です。したがって、ドキュメントは代わりに次のように解釈できます。
この操作中に取得されたロックは、MATERIALIZED VIEWからの読み取り以外の操作を防止します。 REFRESH ... CONCURRENTLYの実行中にマテリアライズドビューを更新しようとすると、最初のロックが解除されるまでキューに入れられます。