関係するテーブルを変更するたびにREFRESH MATERIALIZED VIEW
を呼び出す必要がありますよね?これについては、ウェブ上であまり議論されていないことに驚きました。
これを行うにはどうすればよいですか?
ここでの答えの上半分は私が探しているものだと思います: https://stackoverflow.com/a/23963969/16814
これには危険がありますか?ビューの更新が失敗した場合、呼び出しの更新、挿入などのトランザクションはロールバックされますか? (これは私が欲しいものです...私は思う)
関係するテーブルを変更するたびに
REFRESH MATERIALIZED VIEW
を呼び出す必要がありますか?
はい、PostgreSQL自体は決して自動的に呼び出しません。何らかの方法で呼び出す必要があります。
これを行うにはどうすればよいですか?
これを実現する多くの方法。例を示す前に、 REFRESH MATERIALIZED VIEW
command はAccessExclusiveモードでビューをブロックするため、作業中はSELECT
も実行できないことに注意してください。表。
ただし、バージョン9.4以降を使用している場合は、CONCURRENTLY
オプションを指定できます。
REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
これはExclusiveLockを取得し、SELECT
クエリをブロックしませんが、オーバーヘッドが大きくなる可能性があります(変更されたデータの量に依存します。それでも、2つのREFRESH
コマンドを同時に実行することはできません。
これは考慮すべきオプションです。特に、データの読み込みまたはバッチ更新の場合(たとえば、大量の情報/データのみを長時間読み込むシステム)、データを変更または処理するための操作を最後に行うのが一般的であるため、_ [最後に$ var] _操作。
最初に広く使用されているオプションは、何らかのスケジューリングシステムを使用して更新を呼び出すことです。たとえば、cronジョブで同様の設定を行うことができます。
*/30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"
そして、マテリアライズドビューは30分ごとに更新されます。
このオプションは、特にREFRESH
オプションを使用した場合に非常に優れていますが、常に100%最新ではないデータを受け入れることができる場合のみです。 CONCURRENTLY
の有無にかかわらず、CONCURRENTLY
コマンドはクエリ全体を実行する必要があるため、内部クエリの実行に必要な時間を考慮する必要があることに留意してください。 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();
パフォーマンスと同時実行性にいくつかの重大な落とし穴があります。
REFRESH
を使用しても、1つのCONCURRENTLY
は別のREFRESH
をブロックするため、関連するテーブルに対するINSERT/UPDATE/DELETEはシリアル化されます。唯一の状況は、良いアイデアとして、変更が本当にまれかどうかだと思うことができます。
前のオプションの問題は、同期であり、各操作で大きなオーバーヘッドを課すことです。それを改善するために、以前のようなトリガーを使用できますが、それは NOTIFY
operation のみを呼び出します:
CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
NOTIFY refresh_mv, 'my_mv';
RETURN NULL;
END;
$$;
したがって、接続を維持し、 LISTEN
operation を使用してREFRESH
を呼び出す必要性を識別するアプリケーションを構築できます。これをテストするために使用できる素敵なプロジェクトの1つは 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
は1回だけトリガーされます。
Cronオプションとして、これは少し古いデータでむき出しにできる場合にのみ有効ですが、これにはREFRESH
が本当に必要な場合にのみ呼び出されるという利点があるため、オーバーヘッドが少なくなり、データは必要に応じてより近く更新されます。
OBS:私はまだコードと例を試していません。だから誰かが間違いを見つけたり、タイプミスをしたり、それを試して動作する(またはしない)場合は、お知らせください。
MatheusOlによる前回の回答について3つのことを指摘しましょう-pglaterテクノロジーです。
Long_options配列の最後の要素として、 https://linux.die.net/man/3/getopt_long 「配列の最後の要素はゼロで埋める必要があります。」というフレーズだから、それを読む必要があります-
static struct option long_options[] = { //...... {"help", no_argument, NULL, '?'}, {0, 0, 0, 0} };
Malloc/freeについて-free(forchar listen = malloc(...) ;) 不足している。とにかく、mallocが原因でpglaterプロセスがCentOSでクラッシュしました(ただし、Ubuntuではそうではありません-理由はわかりません)。したがって、char配列を使用し、charポインターに配列名を割り当てることをお勧めします(charとchar **の両方に)。多くの場合、それを行う際に型変換を強制する必要があります(ポインターの割り当て)。
char block4[100]; ... password_Prompt = block4; ... char block1[500]; const char **keywords = (const char **)&block1; ... char block3[300]; char *listen = block3; sprintf(listen, "listen %s", id); PQfreemem(id); res = PQexec(db, listen);
次の表を使用して、mdがmature_durationであるタイムアウトを計算します。これは、最新のrefresh(lr)の時点と現在の時刻との時間差です。
md> = callback_delay(cd)==>タイムアウトの場合:0
when md + PING_INTERVAL> = cd ==> timeout:cd-md [= cd-(now-lr)]
md + PING_INTERVAL <cd ==>タイムアウトの場合:PI
このアルゴリズムを実装するには(3番目のポイント)、次のように「lr」を初期化する必要があります-
res = PQexec(db, command); latest_refresh = time(0); if (PQresultStatus(res) == PGRES_COMMAND_OK) {