暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

物化视图+FDW全/增量更新数据

叶同学专栏 2021-04-16
2349

物化视图介绍

创建语法

CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ TABLESPACE tablespace_name ]
    AS query
    [ WITH [ NO ] DATA ]

物化视图像视图一样使用,但是以一种类表的形式保留了结果。之间的主要区别是物化视图不能直接被更新,更新物化视图的话要用命令进行手工更新

REFRESH MATERIALIZED VIEW mymatview;

FDW介绍

FDW,即外部数据封装器,可以访问本地文件、异地的PG数据库或者其它类型的数据库,如ORACLE、MYSQL、MONGODB、REDIS等,但这些需要我们一个个去找来编译安装,PG本身自带的有FILE_FDW和POSTGRES_FDW。

其中使用POSTGRES_FDW时步骤如下

  1. 使用CREATE EXTENSION来安装 postgres_fdw 扩展。

  2. 使用CREATE SERVER创建外部服务器对象, 以表示你想连接的每一个远程数据库。指定除了 user 和 password 之外的连接信息作为该服务器对象的选项。

  3. 使用CREATE USER MAPPING, 为每个要允许访问外部服务器的数据库用户创建用户映射。指定远程用户名和口令作为用户映射的 user 和 password 选项。

  4. 使用CREATE FOREIGN TABLE或IMPORT FOREIGN SCHEMA, 为每一个你想访问的远程表创建一个外部表。外部表的列必须匹配被引用的远程表。但是,如果指定正确的远程名称作为外部表对象的选项,则可以使用与远程表不同的表和/或列名。

现在你只需要从一个外部表SELECT来访问存储在它的底层的远程表中的数据。也可以使用INSERT 、UPDATE 或 DELETE修改远程表(前提是你的用户映射指定的远程用户做这些事情的权限)。

应用示例

异地库192.168.43.176上创建测试表

create table test
(
id int,
info text
);
insert into test select generate_series(1,1),'test';
create unique index index_test_1 on test(id);

本地库192.168.43.175创建fdw及物化视图

创建extension

CREATE EXTENSION postgres_fdw;

创建server

CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '192.168.43.176', port '6432', dbname 'postgres');

创建映射用户

CREATE USER MAPPING FOR postgres
SERVER foreign_server
OPTIONS (user 'postgres'password 'postgres');

创建foreign table

CREATE FOREIGN TABLE test_foreign (
id int,
info text
)
SERVER foreign_server
OPTIONS (schema_name 'public', table_name 'test');

创建物化视图

CREATE MATERIALIZED VIEW IF NOT EXISTS mv_test as
select * from test_foreign 
with no data;

执行全量更新

postgres=# refresh materialized view mv_test ;
REFRESH MATERIALIZED VIEW
postgres=
postgres=# select * from mv_test ;
 id | info 
----+------
  1 | test
(1 row)

异地库176上的test表更新及插入数据

postgres=# update test set info='176';
UPDATE 1
postgres=# insert into test select generate_series(2,2),'test';
INSERT 0 1

执行增量更新报错,物化视图需要有唯一索引

postgres=# refresh materialized view CONCURRENTLY mv_test ;
ERROR:  cannot refresh materialized view "public.mv_test" concurrently
HINT:  Create a unique index with no WHERE clause on one or more columns of the materialized view.

物化视图建索引再重试,增量更新成功

postgres=# create unique index index_mv_test_1 on mv_test(id);
CREATE INDEX
postgres=# refresh materialized view CONCURRENTLY mv_test ;
REFRESH MATERIALIZED VIEW
postgres=# select * from mv_test ;
 id | info 
----+------
  1 | 176
  2 | test

为什么我们不直接查询fdw外部表,而要多做一步用物化视图呢?因为查询物化视图比查询fdw外部表要快很多,fdw外部表每次都要远程去访问数据的,而物化视图是保存表数据到本地的。通过查询计划可以知道用物化视图查询的优势。

postgres=# explain select * from test_foreign ;
                               QUERY PLAN                               
------------------------------------------------------------------------
 Foreign Scan on test_foreign  (cost=100.00..150.95 rows=1365 width=36)
(1 row)

postgres=# explain select * from mv_test ;
                       QUERY PLAN                       
--------------------------------------------------------
 Seq Scan on mv_test  (cost=0.00..1.01 rows=1 width=36)
(1 row)

小结

  • 物化视图的全量刷新会有锁,其它事务查询这视图时会等待。

  • 物化视图增量刷新功能在9.4版本之后才有,需要有唯一索引,并且其它事务查询这视图时不会等待。当物化视图还未被填充数据时,这个选项不能被使用。

  • 当数据量较大时,物化视图全量刷新比增量刷新速度快,CONCURRENTLY原理是通过索引关联、其它所有字段不相等的join查询更新的。

  • 物化视图+FDW适合对数据库实时性不高的场景。


文章转载自叶同学专栏,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论