我有两张桌子,一张父表和一张子表。 父表和子表通过外键链接在一起。 父表和子表都有自己的主键。
create table parent (
parent_id integer primary key,
data ...
);
create table child(
child_id integer primary key,
parent_id integer references parent(parent_id),
data ...
);
我想制作一对物化视图来存储父表和子表的数据副本,所以我制作了2个物化视图。
create materialized view view_parent as select * from parent;
create unique index on view_parent(parent_id);
create materialized view view_child as select * from child;
create unique index on view_child(child_id);
现在,当我决定刷新视图时,我预见的问题是,如果您根据刷新物化视图的顺序不断添加到基表,您可能会获得没有父级的子行(如果您先添加父级) )或没有子项的父行(如果您先处理子项)。 删除可能会导致两个表之间出现类似的问题。
我认为可以避免这种情况的一种方法是在事务中进行刷新,因为至少如果您这样做,刷新应该在其开发的同一阶段查看父表,但是这会锁定多少系统? 理想情况下,我希望对两个父表进行快照并刷新物化视图,允许用户查看物化视图而不锁定它们,并允许写入父表,同样也不将用户锁定。 在事务中刷新物化视图是否会锁定物化视图的读取器或父表的写入器?
如果普通视图不适合您,并且您想要复制数据,您可以按以下步骤操作:
创建新架构
在新模式中创建物化视图而不使用
CONCURRENTLY
,以便您可以在单个事务中创建所有物化视图
在某个时刻,终止使用旧物化视图模式的所有会话,删除模式并重命名新模式
最后一步可以按如下方式进行:
在一个会话中,运行
SELECT pg_backend_pid();
DROP SCHEMA oldschema CASCADE;
在另一个会话中,运行
SELECT pg_terminate_backend(s)
FROM unnest(pg_blocking_pids(12345));
其中 12345 是第一个语句找到的进程 ID。
一旦
DROP SCHEMA
完成(应该很快),第一个会话就会重命名新模式:
ALTER SCHEMA newschema RENAME TO oldschema;