PostgreSQL dblink无法进行索引查询怎么办?

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跟踪函数内部执行计划方法
在这里插入图片描述
通过跟踪我们可以发现,上面的查询其实是分成两步:

  1. 在远端库(bill)中执行select * from t1; 返回了10W条数据;
  2. 将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

猜你喜欢

转载自blog.csdn.net/weixin_39540651/article/details/114978082
今日推荐