使用规则或通知自动刷新物化视图
我有一个PostgreSQL 9.3数据库的实体化视图,很less发生变化(大约每天两次)。 但是当它发生时,我想立即更新它的数据。
以下是我到目前为止的想法:
有一个物化视图mat_view
,它使用一些join语句从表table1
和table2
获取数据。
每当table1
或table2
东西发生变化,我已经有一个触发器,更新一个小的configuration表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
和第二行也是一样的。
显然,如果need_update
为TRUE,则物化视图必须刷新。
更新 :由于物化视图不支持规则(如下面评论中提到的@pozs),我会更进一步。 我会创build一个虚拟视图v_mat_view
定义“ SELECT * FROM mat_view
”。 当用户在这个视图上做一个SELECT时,我需要创build一个规则ON SELECT,它执行以下操作:
- 检查
mat_view
是否应该更新(SELECT 1 FROM config WHERE mat_view_name='mat_view' AND need_update=TRUE
) - 用
UPDATE config SET need_update=FALSE where mat_view_name='mat_view'
重置need_update
标志UPDATE config SET need_update=FALSE where mat_view_name='mat_view'
-
REFRESH MATERIALIZED VIEW mat_view
- 并最终做原始的SELECT语句,但
mat_view
作为目标。
UPDATE2 :我尝试创build上面的步骤:
创build一个处理上述四点的函数:
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;
创build真正从函数mat_view_selector
select的视图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本身中select相比:
# 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
所以基本上它工作,但性能可能是一个问题。
任何人有更好的想法? 如果不是,那么我将不得不在应用程序逻辑中实现它,或者更糟糕的是:运行一个简单的每分钟运行一次的cronjob。 🙁
PostgreSQL 9.4将REFRESH CONCURRENTLY
添加到物化视图。
这可能是您在描述尝试设置物化视图的asynchronous更新时所要查找的内容。
从物化视图select的用户将看到不正确的数据,直到刷新完成,但在许多情况下,使用物化视图,这是一个可以接受的折衷。
使用一个语句级触发器来监视基础表的任何变化,然后同时刷新实例化视图。
在为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();
这样你的物化视图总是最新的。 这个简单的解决scheme可能难以接受频繁的插入/更新和零星的select。 在你的情况下(很less改变一天两次),它理想上符合你的需求。
要实现物化视图的延迟刷新 ,您需要以下function之一:
- asynchronous触发
- 在select之前触发
- 规则select之前
Postgres没有他们,所以似乎没有明确的 postgres解决scheme。
考虑到这一点,我会考虑mat_viewselect包装函数,例如
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;
如果在实践中是可以接受的,取决于我不知道的细节。