我对 PostgreSQL 9.3 数据库有一个物化视图,该数据库很少更改(大约每天两次)。但当它发生时,我想立即更新其数据。
到目前为止,这是我的想法:
有一个物化视图mat_view
它从表中获取数据table1
and table2
使用一些连接语句。
每当有东西在table1
or 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,则必须刷新物化视图。
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
- 最后执行原始 SELECT 语句,但使用
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。