[解決済み] マテリアライズド・ビューを常に最新の状態に保つにはどうすればよいですか?
質問
を呼び出す必要がありますね。
REFRESH MATERIALIZED VIEW
を呼び出す必要がありますね?これについての議論がウェブ上であまり見つからないことに驚いています。
これを行うにはどうしたらいいでしょうか?
ここの回答の上半分が、私が求めているものだと思います。 https://stackoverflow.com/a/23963969/168143
これには何か危険があるのでしょうか?ビューの更新が失敗した場合、updateやinsertなどを実行したトランザクションはロールバックされるのでしょうか?(これは私が望んでいることです...私はそう思います)
どのように解決するのですか?
<ブロッククオート
を呼び出す必要がありますね。
REFRESH MATERIALIZED VIEW
を呼び出す必要がありますね?
はい、PostgreSQL単体では自動的には呼び出されませんので、何らかの方法で行う必要があります。
<ブロッククオートどのようにすればよいのでしょうか?
多くの方法があります。いくつか例を挙げる前に、以下のことを心に留めておいてください。
REFRESH MATERIALIZED VIEW
コマンド
は AccessExclusive モードでビューをブロックするので、これが動作している間は
SELECT
を実行することもできません。
とはいえ、バージョン9.4以降であれば、テーブルの上に渡すのは
CONCURRENTLY
オプションを指定することができます。
REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
これはExclusiveLockを取得し、ブロックしない。
SELECT
クエリをブロックしませんが、オーバーヘッドが大きくなります (変更されたデータの量に依存します。変更された行が少ない場合は、より高速になる可能性があります)。それでも、2つの
REFRESH
コマンドを同時に実行することはできません。
手動でリフレッシュ
考慮すべきオプションのひとつです。特にデータのロードや一括更新の場合 (たとえば、大量の情報/データを長い時間かけてロードするシステム)、データを修正または処理するための操作を最後に行うのが一般的なので、単純に
REFRESH
操作を含めることができます。
REFRESH操作のスケジューリング
最初の、そして広く使われているオプションは、リフレッシュを呼び出すために何らかのスケジュールシステムを使うことです。例えば、cronジョブでそのように設定することができます。
*/30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"
そして、30分ごとにマテリアライズド・ビューがリフレッシュされます。
考察
このオプションは、特に
CONCURRENTLY
オプションと一緒に使うのがいいでしょう。ただし、データが常に100%最新でないことを受け入れられる場合に限ります。このオプションの有無にかかわらず
CONCURRENTLY
の有無にかかわらず
REFRESH
コマンドはクエリ全体を実行する必要があるので、内部のクエリを実行するのに必要な時間を考慮してから
REFRESH
.
トリガーを使ったリフレッシュ
もう一つの選択肢は
REFRESH MATERIALIZED VIEW
をトリガー関数で呼び出すことです。
CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
RETURN NULL;
END;
$$;
そして、ビュー上の変更を伴うテーブルでは、そうします。
CREATE TRIGGER tg_refresh_my_mv AFTER INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH STATEMENT EXECUTE PROCEDURE tg_refresh_my_mv();
考察
パフォーマンスと並行性に関して、いくつかの重大な落とし穴があります。
- すべての INSERT/UPDATE/DELETE 操作は、クエリを実行しなければなりません (MV を検討している場合、これは遅くなる可能性があります)。
-
であっても
CONCURRENTLY
は、1つのREFRESH
はまだ別のものをブロックしているので、関連するテーブルの INSERT/UPDATE/DELETE はすべてシリアライズされます。
私が良いアイデアとして考えられる唯一の状況は、変更が本当にまれである場合です。
LISTEN/NOTIFY を使用してリフレッシュする
前のオプションの問題は、それが同期であり、各操作で大きなオーバーヘッドを課すということです。これを改善するために、以前のようにトリガーを使用することができますが、そのトリガーは
NOTIFY
操作
:
CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
NOTIFY refresh_mv, 'my_mv';
RETURN NULL;
END;
$$;
ということで、接続を維持するアプリケーションを作り、そのアプリケーションで
LISTEN
操作
を呼び出す必要性を識別するために
REFRESH
. これをテストするために使える素晴らしいプロジェクトのひとつが
pgsidekick
このプロジェクトでは、シェルスクリプトを使って
LISTEN
をスケジュールすることができます。
REFRESH
としています。
pglisten --listen=refresh_mv --print0 | xargs -0 -n1 -I? psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY ?;"
あるいは
pglater
(また
pgsidekick
を呼び出さないようにするためです。
REFRESH
を非常に頻繁に使用します。例えば、次のようなトリガーを使って、それを
REFRESH
と表示されますが、1分(60秒)以内です。
CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
NOTIFY refresh_mv, '60 REFRESH MATERIALIZED VIEW CONCURRENLTY my_mv';
RETURN NULL;
END;
$$;
というわけで、これは
REFRESH
を 60 秒以内に呼び出したり、また
NOTIFY
を60秒以内に何度も繰り返すと
REFRESH
は一度だけ起動されます。
考察
cronオプションと同様に、このオプションも、多少古いデータでも我慢できる場合にのみ使用するとよいでしょう。
REFRESH
が本当に必要なときだけ呼び出されるので、オーバーヘッドが少なく、また、必要なときに近いタイミングでデータが更新されるという利点があります。
OBS: 私はまだコードと例を実際に試していないので、もし誰かが間違いやタイプミスを見つけたり、試してみてうまくいったり(あるいはいかなかったり)したら、教えてください。
関連
-
postgresql 重複データ削除 ケーススタディ
-
Postgresqlの行から列への高度な応用と要約のアイデア
-
単語をソートするカスタム関数とそれをPostgreSQLで使用する(実装コード)
-
Postgresql+Springboot ymlの基本的な使い方
-
[解決済み] PostgreSQLで重複して更新された場合の挿入?
-
[解決済み] Postgres の全テーブルの行数を求めるには?
-
[解決済み] PostgreSQLのクエリを記録する方法は?
-
[解決済み】Mac OS XでPostgreSQLサーバーを起動するには?
-
[解決済み] varcharフィールドの型をintegerに変更する。"自動的にinteger型にキャストすることはできません"
-
[解決済み] クエリプランにおける「ビットマップヒープスキャン」とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PostgreSQLで文字列が対象の文字列を含むかどうかを判断する様々な方法
-
postgresql いくつかのメソッドは、要約の重複するデータを削除する
-
サーバーに接続できませんでした:接続拒否(0x0000274D/10061)
-
[解決済み] postgres の主キー配列が同期しなくなったときにリセットする方法は?
-
[解決済み] 'ユーザー "postgres" のパスワード認証に失敗しました'
-
[解決済み] PostgresでInsert文のUUIDを生成する?
-
[解決済み] PostgreSQLの場合。PostgreSQLですべてのテーブルのOWNERを同時に変更する
-
[解決済み] OracleのViewsとMaterialized Viewsの違いは何ですか?
-
[解決済み] PostgreSQLのINSERT ON CONFLICT UPDATE(upsert)は除外された値をすべて使用します。
-
[解決済み] PostgreSQLでタイムスタンプの差を秒単位で求める