postgresql中我们访问其它数据库常常使用dblink和fdw这两种模块,在官方文档中也是更加建议使用fdw。
不知道大家在使用dblink时有没有碰到过这种情况,对于一个常常需要执行的查询,我们往往会在本地创建一个视图来替换,这也是在官方文档中建议的一个方案。但是如果对这种视图进行where过滤时是没办法使用到索引的,这和本地的视图有很大的区别。
我们先来看看本地视图的情况:
对本地的一张表t2创建一个视图:
bill@postgres=>\d t2
Table "public.t2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | |
info | text | | |
Indexes:
"idx_t2" btree (id)
bill@postgres=>create view v_t2 as select * from t2;
CREATE VIEW
这种情况我们对视图v_t2使用索引查询是没问题的:
bill@postgres=>explain select * from v_t2 where id < 10;
QUERY PLAN
------------------------------------------------------------------
Index Scan using idx_t2 on t2 (cost=0.29..3.04 rows=9 width=37)
Index Cond: (id < 10)
(2 rows)
接下来是dblink的情况:
创建dblink连接:
select dblink_connect('mydblink','hostaddr=127.0.0.1 port=1921 dbname=bill user=bill password=bill');
创建视图(t1和本地的t2结构一致):
create view v_dblink as select * from dblink('mydblink','select * from t1;') as t1(id int,info text);
再看看查询v_dblink是什么情况:
bill@postgres=>explain select * from v_dblink where id < 10;
QUERY PLAN
------------------------------------------------------------------
Function Scan on dblink t1 (cost=0.00..12.50 rows=333 width=36)
Filter: (id < 10)
(2 rows)
这里我们没法看到详细的信息,因为视图中使用了函数dblink,我们可以使用auto_trace来跟踪函数内部的执行情况:
PostgreSQL跟踪函数内部执行计划方法
通过跟踪我们可以发现,上面的查询其实是分成两步:
- 在远端库(bill)中执行select * from t1; 返回了10W条数据;
- 将10W条数据传到本地库(postgres)中进行过滤。
那么这样如果在dblink大表上创建这样的视图确实对性能是挺大的影响,除非在创建dblink时加上条件:
select * from dblink('mydblink','select * from t1 < 10;') as t1(id int,info text);
那么这样显然不是我们的本意,如果想要进行其它条件的where过滤又要重新创建dblink查询。
这似乎没法两全,这个时候我们使用fdw便可以解决此类问题。
创建外部表:
user01@db01=>CREATE SERVER db02
db01-# FOREIGN DATA WRAPPER postgres_fdw
db01-# OPTIONS (host '127.0.0.1', port '1921', dbname 'db02');
CREATE SERVER
user01@db01=>CREATE USER MAPPING FOR user01
db01-# SERVER db02
db01-# OPTIONS (user 'user02', password 'bill');
CREATE USER MAPPING
user01@db01=>CREATE FOREIGN TABLE t1(
db01(# id int, crt_Time timestamp, info text, c1 int)
db01-# SERVER db02
db01-# OPTIONS (schema_name 'public', table_name 'table1');
CREATE FOREIGN TABLE
对外部表t1进行where查询:
select * from t1 where id < 10;
可以看到在远端库db02上进行了索引查询。这是因为fdw能够将本地的语句push到远端去执行,当然目前仅支持:内置数据类型、immutable操作符、immutable函数。
可见fdw的功能确实更加强大,这也是为什么建议大家使用fdw而不是dblink的原因。
参考链接:
PostgreSQL fdw详解
https://www.postgresql.org/docs/13/dblink.html
https://www.postgresql.org/docs/13/postgres-fdw.html