PostgreSQL 9.3データベースのマテリアライズドビューがあり、めったに変更されません(1日に2回程度)。しかし、そうなったら、すぐにデータを更新したいと思います。
ここに私がこれまで考えていたことがあります:
マテリアライズドビューmat_view
があります。これは、結合ステートメントを使用して、テーブルtable1
およびtable2
からデータを取得します。
table1
またはtable2
の何かが変更されるたびに、すでに小さな構成テーブルconfig
を更新するトリガーがあります。
table_name | mat_view_name | need_update
-----------+---------------+------------
table1 | mat_view | TRUE/FALSE
table2 | mat_view | TRUE/FALSE
したがって、table1
のいずれかが変更された場合(すべてのステートメントのUPDATEおよびDELETEのトリガーがある場合)、最初の行のフィールドneed_update
はTRUE
に設定されます。 table2
と2行目も同様です。
明らかに、need_update
がTRUEの場合、マテリアライズドビューを更新する必要があります。
[〜#〜] update [〜#〜]:マテリアライズドビューはルールをサポートしていないため(@pozsが以下のコメントで言及されているように)、さらに一歩進めます。定義 "v_mat_view
"でダミービューSELECT * FROM mat_view
を作成します。ユーザーがこのビューでSELECTを実行すると、次のことを行うルールON SELECTを作成する必要があります。
mat_view
を更新する必要があるかどうかを確認します(SELECT 1 FROM config WHERE mat_view_name='mat_view' AND need_update=TRUE
)need_update
フラグをUPDATE config SET need_update=FALSE where mat_view_name='mat_view'
でリセットしますREFRESH MATERIALIZED VIEW mat_view
mat_view
をターゲットとして使用します。PDATE2:上記の手順を作成してみました:
上記の4つのポイントを処理する関数を作成します。
CREATE OR REPLACE FUNCTION mat_view_selector()
RETURNS SETOF mat_view AS $body$
BEGIN
-- here is checking whether to refresh the mat_view
-- then return the select:
RETURN QUERY SELECT * FROM mat_view;
END;
$body$ LANGUAGE plpgsql;
関数v_mat_view
から実際に選択するビューmat_view_selector
を作成します。
CREATE TABLE v_mat_view AS SELECT * from mat_view LIMIT 1;
DELETE FROM v_mat_view;
CREATE RULE "_RETURN" AS
ON SELECT TO v_mat_view
DO INSTEAD
SELECT * FROM mat_view_selector();
-- this also converts the empty table 'v_mat_view' into a view.
# explain analyze select field1 from v_mat_view where field2 = 44;
QUERY PLAN
Function Scan on mat_view_selector (cost=0.25..12.75 rows=5 width=4)
(actual time=15.457..18.048 rows=1 loops=1)
Filter: (field2 = 44)
Rows Removed by Filter: 20021
Total runtime: 31.753 ms
mat_view自体からの選択と比較して:
# explain analyze select field1 from mat_view where field2 = 44;
QUERY PLAN
Index Scan using mat_view_field2 on mat_view (cost=0.29..8.30 rows=1 width=4)
(actual time=0.015..0.016 rows=1 loops=1)
Index Cond: (field2 = 44)
Total runtime: 0.036 ms
本質的には機能しますが、パフォーマンスが問題になる場合があります。
誰もがより良いアイデアを持っていますか?そうでない場合は、アプリケーションロジックでそれを何らかの方法で実装する必要があります。さらに悪いことには、1分ごとに実行される単純なcronjobを実行します。 :-(
PostgreSQL 9.4追加REFRESH CONCURRENTLY
からマテリアライズドビューへ。
これは、マテリアライズドビューの非同期更新をセットアップしようとするときに説明するものです。
マテリアライズドビューから選択するユーザーには、更新が完了するまで誤ったデータが表示されますが、マテリアライズドビューを使用する多くのシナリオでは、これは許容できるトレードオフです。
基礎となるテーブルの変更を監視し、マテリアライズドビューを同時に更新するステートメントレベルトリガーを使用します。
table1
およびtable2
の各ステートメントの挿入/更新/削除/切り捨て後に、トリガーのビューを更新する必要があります。
create or replace function refresh_mat_view()
returns trigger language plpgsql
as $$
begin
refresh materialized view mat_view;
return null;
end $$;
create trigger refresh_mat_view
after insert or update or delete or truncate
on table1 for each statement
execute procedure refresh_mat_view();
create trigger refresh_mat_view
after insert or update or delete or truncate
on table2 for each statement
execute procedure refresh_mat_view();
このようにして、マテリアライズドビューは常に最新の状態になります。この単純なソリューションは、頻繁な挿入/更新および散発的な選択では受け入れがたい場合があります。あなたの場合(1日2回ほど変更されることはほとんどありません)、理想的にはあなたのニーズに合っています。
マテリアライズドビューのdeferred refreshを実現するには、次の機能のいずれかが必要です。
Postgresにはそれらがないため、clear postgresソリューションはないようです。
これを考慮に入れて、mat_viewの選択用のラッパー関数を検討します。
CREATE OR REPLACE FUNCTION select_from_mat_view(where_clause text)
RETURNS SETOF mat_view AS $body$
BEGIN
-- here is checking whether to refresh the mat_view
-- then return the select:
RETURN QUERY EXECUTE FORMAT ('SELECT * FROM mat_view %s', where_clause);
END;
$body$ LANGUAGE plpgsql;
実際に受け入れられるかどうかは、私が知らない詳細に依存します。