我在PostgreSQL 9.3数据库上有一个物化视图,该数据库很少更改(大约每天两次)。但是当它发生时,我想及时更新其数据。
到目前为止,我正在思考这个问题:
有一个实体化视图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
和第二行也是如此。
显然,如果need_update
为TRUE,则必须刷新实体化视图。
更新:
由于物化视图不支持规则(如下面评论中提到的@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
为目标。UPDATE2 : 我尝试创建上面的步骤:
创建一个处理上述四点的函数:
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
所以基本上它可以工作,但性能可能是一个问题。
任何人都有更好的想法? 如果没有,那么我将不得不以某种方式在应用程序逻辑中实现它,或者更糟糕的是:运行一个每分钟运行一次的简单cronjob。 : - (
答案 0 :(得分:98)
您应该在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();
通过这种方式,您的物化视图始终是最新的。对于频繁的插入/更新和零星选择,这个简单的解决方案可能很难接受。 在您的情况下(很少每天更换两次),它非常适合您的需求。
要实现物化视图的延迟刷新,您需要以下功能之一:
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;
如果在实践中可接受取决于我不知道的细节。
答案 1 :(得分:24)
PostgreSQL 9.4将REFRESH CONCURRENTLY
添加到物化视图。
当您描述尝试设置实体化视图的异步更新时,这可能是您正在寻找的。 p>
从物化视图中选择的用户在刷新完成之前将看到不正确的数据,但在使用物化视图的许多场景中,这是可接受的权衡。
使用语句级触发器监视基础表以查找任何更改,然后同时刷新实例化视图。