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


13

ドキュメントによると:

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

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

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

私が持っていたそれをリフレッシュするマテリアライズド・ビューの最後のリフレッシュ時間を確認機能をして、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値を確認します。refreshingtrueの場合、マテリアライズドビューを更新しようとしないでください。

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 2018年

それは意見の問題です。もちろん、それが役立つと思うなら、もちろん論理を維持できます。ただし、関数は競合状態の影響を受けるため、100%信頼できるわけではないことに注意してください。
mustaccio 2018年

pg_locksをチェックして、マットビューを参照しているものが存在するかどうかを確認するのは現実的だと思いますか?
ffflabs 2018年

繰り返しになりますが、競合状態が発生する可能性がありpg_locksます。チェックと更新の開始の間にロックが設定される可能性があります。ロックの競合に対処する適切な方法は、タイムアウトを設定してエラーを処理することです。
mustaccio 2018年

3

mustaccioによって指摘されているように、この質問はPostgresリフレッシュマテリアライズドビューロックと大幅に重複しています

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

つまり、具体的には、明示的なロックに関するPostgreSQLのマニュアルページ(リンクはPostGres 10の現在のバージョンのページへのリンクです)によると、ロックを取得REFRESH MATERIALIZED VIEW CONCURRENTLYEXCLUSIVEます。EXCLUSIVEロックは、他のすべてのロックをブロックするように表示される以外 ACCESS SHARE、他の含まれている- EXCLUSIVEロックを。

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


ありがとうございました。@mustaccioが私の質問にもっと具体的になるように彼のテキストを編集したため、私はまだ@mustaccioの回答を承認済みとしてマークしました。
ffflabs 2018年

0

mustaccioRDFozzの回答のおかげで、私はようやくREFRESH ... CONCURRENTLY、排他的ロックを取得することがPostgreSQLのドキュメントに記載されている理由であることを理解しました。

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.