热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[译文]PostgreSQL14中的postgres_fdw增强

本文将试着了解并找出与PostgreSQL14与版本13相比发生了哪些变化,看看哪些方面有所改进,以及哪些行为发生了变化。将所有内容放在一个博客中需要花费数周时间编写和阅读数天时间

本文将试着了解并找出与PostgreSQL 14 与版本 13 相比发生了哪些变化,看看哪些方面有所改进,以及哪些行为发生了变化。将所有内容放在一个博客中需要花费数周时间编写和阅读数天时间,因此本文将仅关注 PostgreSQL 版本 14 的 GA 版本中外部数据包装器中预期的更改。

外部数据包装器 (FDW) 提供了一种机制,通过该机制可以使用常规 SQL 查询访问驻留在 PostgreSQL 之外的数据。然而,有许多不同的 FDW 可用,并且 PostgreSQL 带有“文件 FDW”和“PostgreSQL FDW”。PostgreSQL FDW 可能看起来违反直觉,但它是一个非常有用的功能。这个 FDW 有一些非常有用的更新。

所以,让我们开始了解发生了什么变化。


性能特点

如果您已经在任何用例中使用 PostgreSQL FDW,请注意性能改进。


1 – 并行/异步外部扫描

(允许引用多个外部表的查询并行执行外部表扫描)

跨多个服务器执行时,远程聚合和远程连接可能是性能噩梦。性能优势来自 ForeignScan 的并行化,现在可以异步并行执行。以前的顺序执行很慢,在某些情况下,太慢了。为此,添加了一个新的服务器选项“async_capable”,它允许并行规划和执行 ForeignScan。

创建服务器和用户映射

-- Create foreign server 1.
CREATE SERVER postgres_svr1
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '127.0.0.1', async_capable "true");

-- Create foreign server 2.
CREATE SERVER postgres_svr2
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '127.0.0.1', async_capable "true");

CREATE USER MAPPING FOR vagrant
SERVER postgres_svr1
OPTIONS (user 'postgres', password 'pass');

CREATE USER MAPPING FOR vagrant
SERVER postgres_svr2
OPTIONS (user 'postgres', password 'pass');

创建本地表

CREATE TABLE parent_local (a INTEGER, b CHAR, c TEXT, d VARCHAR(255)) PARTITION BY RANGE (a);
CREATE TABLE child_local1 (a INTEGER, b CHAR, c TEXT, d VARCHAR(255));
CREATE TABLE child_local2 (a int, b CHAR, c text, d VARCHAR(255));
GRANT ALL ON child_local1 to postgres;
GRANT ALL ON child_local2 to postgres;

创建外部表

CREATE FOREIGN TABLE parent_remote1
PARTITION OF parent_local VALUES FROM 1000 TO 2000
SERVER postgres_svr1 OPTIONS table_name 'child_local1');
CREATE FOREIGN TABLE parent_remote2
PARTITION OF parent_local
FOR VALUES FROM 2000 TO 3000
SERVER postgres_svr2 OPTIONS table_name 'child_local2');

现在尝试一下,并查看计划树,现在您可以在树中看到两个 Async Foreign 计划。

CREATE TABLE sample_table (a INTEGER, b CHAR, c TEXT, d VARCHAR(255));
EXPLAIN (VERBOSE, COSTS OFF)
INSERT INTO sample_table SELECT * FROM parent_local WHERE a % 100 = 0;
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Insert on public.sample_table
   ->  Append
         ->  Async Foreign Scan on public.parent_remote1 parent_local_1
               Output: parent_local_1.a, parent_local_1.b, parent_local_1.c, parent_local_1.d
               Remote SQL: SELECT a, b, c, d FROM public.child_local1 WHERE (((a % 100) = 0))
         ->  Async Foreign Scan on public.parent_remote2 parent_local_2
               Output: parent_local_2.a, parent_local_2.b, parent_local_2.c, parent_local_2.d
               Remote SQL: SELECT a, b, c, d FROM public.child_local2 WHERE (((a % 100) = 0))
(8 rows)

2 – 批量插入

(允许 postgres_fdw 批量插入行。)

现在批量插入功能已添加到外部数据包装器中,并且 postgres_fdw 现在支持该功能。其他外部数据包装器有机会实现批量插入。一个完整的博客可以在这里看到。


功能特点


1 – TRUNCATE 命令

(允许 TRUNCATE 对外部表进行操作。)

外部数据包装器得到增强,以支持将外部表作为目标的 TRUNCATE 命令。这意味着它发出发送到外部服务器并在表上执行的 TRUNCATE 命令。幸运的是,这个功能是在 postgres_fdw 中实现的。这是一个例子。

CREATE SERVER postgres_svr 
       FOREIGN DATA WRAPPER postgres_fdw 
       OPTIONS (host '127.0.0.1');
CREATE USER MAPPING FOR vagrant
       SERVER postgres_svr
       OPTIONS (user 'postgres', password 'pass');
CREATE FOREIGN TABLE foo_remote (a INTEGER,
                                 b CHAR,
                                 c TEXT,
                                 d VARCHAR(255))
       SERVER postgres_svr
       OPTIONS(table_name 'foo_local');

现在可以使用 TRUNCATE 命令截断外部表。

postgres=# TRUNCATE foo_remote;
TRUNCATE TABLE

2 – 限制子分区

(如果 IMPORT FOREIGN SCHEMA … LIMIT TO 指定,则允许 postgres_fdw 导入表分区。)

该postgres_fdw不允许表分区的进口,因为数据可以使用根分区访问。但是如果用户想要导入分区表分区,PostgreSQL 14 添加了一个名为“LIMIT TO”的新选项。在远程机器上创建一个新模式并添加一个父表“foo_schema.foo_table_parent”和一个子表“foo_schema.foo_table_child”。

postgres=# \d+ foo_schema.*
                                   Table "foo_schema.foo_table_child"
 Column |  Type   | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
 a      | integer |           |          |         | plain   |             |              | 
Partition of: foo_schema.foo_table_parent FOR VALUES FROM (0) TO (10)
Partition constraint: ((a IS NOT NULL) AND (a >= 0) AND (a <10))
Access method: heap
                            Partitioned table "foo_schema.foo_table_parent"
 Column |  Type   | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
 a      | integer |           |          |         | plain   |             |              | 
Partition key: RANGE (a)
Partitions: foo_schema.foo_table_child FOR VALUES FROM (0) TO (10)

导入模式不指定LIMIT TO,可以看到只导入了父表。

IMPORT FOREIGN SCHEMA foo_schema FROM SERVER postgres_svr INTO bar_schema;
postgres=# \d+ bar_schema.*
Foreign table "bar_schema.foo_table_parent"
Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description
--------+---------+-----------+----------+---------+-------------------+---------+--------------+-------------
a | integer | | | | (column_name 'a') | plain | |
Server: postgres_svr
FDW options: (schema_name 'foo_schema', table_name 'foo_table_parent')

如果您在 LIMIT TO 子句中明确指定了分区表,那么它将导入该表。

postgres=# IMPORT FOREIGN SCHEMA foo_schema LIMIT TO (foo_table_parent, foo_table_child)
FROM SERVER loopback INTO bar_schema;
IMPORT FOREIGN SCHEMA
postgres=# \d+ bar_schema.*
                                  Foreign table "bar_schema.foo_table_child"
 Column |  Type   | Collation | Nullable | Default |    FDW options    | Storage | Stats target | Description 
--------+---------+-----------+----------+---------+-------------------+---------+--------------+-------------
 a      | integer |           |          |         | (column_name 'a') | plain   |              | 
Server: loopback
FDW options: (schema_name 'foo_schema', table_name 'foo_table_child')
                                 Foreign table "bar_schema.foo_table_parent"
 Column |  Type   | Collation | Nullable | Default |    FDW options    | Storage | Stats target | Description 
--------+---------+-----------+----------+---------+-------------------+---------+--------------+-------------
 a      | integer |           |          |         | (column_name 'a') | plain   |              | 
Server: loopback
FDW options: (schema_name 'foo_schema', table_name 'foo_table_parent')

3 – 活动和有效的连接列表

(添加 postgres_fdw 函数 postgres_fdw_get_connections 报告打开的外部服务器连接)

添加了一个新函数 postgres_fdw_get_connections()。该函数将打开的连接名称本地会话返回到 postgres_fdw 的外部服务器。它还输出连接的有效性。

postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
    server_name    | valid 
-------------------+-------
 postgres_svr      | t
 postgres_svr_bulk | t
(2 rows)

现在断开所有连接连接并再次尝试查询。

postgres=# SELECT 1 FROM postgres_fdw_disconnect_all();
?column?
----------
1
(1 row)

postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
server_name | valid
-------------+-------
(0 rows)

4 – 保持联系

(添加 postgres_fdw 函数以丢弃缓存连接)

添加了一个新选项 keep_connections 以保持连接处于活动状态,以便后续查询可以重用它们。默认情况下,此选项处于开启状态,但关闭时,连接将在事务结束时被丢弃。

关闭该选项

ALTER SERVER loopback OPTIONS (keep_connections 'off');

使用远程查询建立连接。

postgres=# BEGIN;
BEGIN

postgres=*# select * from foo_remote;
a | b | c | d
---+---+---+---
(0 rows)

postgres=*# END;
COMMIT

postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
server_name | valid
-------------+-------
(0 rows)

将 keep_connections 选项设置为

Shell
ALTER SERVER postgres_svr options (set keep_connections 'on');

postgres=# BEGIN;
BEGIN
postgres=*# select * from foo_remote;
 a | b | c | d 
---+---+---+---
(0 rows)
-- Establish the connection using the remote query.
postgres=*# END;
COMMIT
postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
 server_name  | valid 
--------------+-------
 postgres_svr | t
(1 row)

5 – 重新建立断开的连接

(如有必要,允许 postgres_fdw 重新建立外部服务器连接)

以前当远程服务器重新启动并且 postgres_fdw 连接中断时,会因为缓存的连接不再可用而引发错误。这在 PostgreSQL 中是固定的,无论如何,连接断开并且缓存中不再存在,并且 postgres_fdw 将建立连接。


结论

非常有希望的是,外部数据包装器 API 在每个版本中都在扩展,但 PostgreSQL 14 提供了一些以用户为中心的新功能。与性能相关的改进为在许多相关用例中使用 FDW 提供了另一个理由。该功能肯定会在接下来的几个版本中添加,使这些功能更加高效且易于使用。



推荐阅读
author-avatar
用户gokk5efqd3
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有