本文将试着了解并找出与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 SERVER postgres_svr1
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '127.0.0.1', async_capable "true");
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)
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 提供了另一个理由。该功能肯定会在接下来的几个版本中添加,使这些功能更加高效且易于使用。