使用规则或通知自动刷新物化视图

我有一个PostgreSQL 9.3数据库的实体化视图,很less发生变化(大约每天两次)。 但是当它发生时,我想立即更新它的数据。

以下是我到目前为止的想法:

有一个物化视图mat_view ,它使用一些join语句从表table1table2获取数据。

每当table1table2东西发生变化,我已经有一个触发器,更新一个小的configuration表config组成

 table_name | mat_view_name | need_update -----------+---------------+------------ table1 | mat_view | TRUE/FALSE table2 | mat_view | TRUE/FALSE 

因此,如果table1任何内容发生更改(每个语句都有UPDATE和DELETE上的触发器),则第一行中的need_update字段将设置为TRUEtable2和第二行也是一样的。

显然,如果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_selectorselect的视图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的用户将看到不正确的数据,直到刷新完成,但在许多情况下,使用物化视图,这是一个可以接受的折衷。

使用一个语句级触发器来监视基础表的任何变化,然后同时刷新实例化视图。

在为table1table2上的每个语句插入/更新/删除/截断之后,您应该刷新触发器中的视图。

 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; 

如果在实践中是可以接受的,取决于我不知道的细节。