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

[译文] PostgreSQL 14 中的 postgres_fdw 增强

原创 Ibrar Ahmed 2021-08-24
2187

本文将试着了解并找出与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 提供了另一个理由。该功能肯定会在接下来的几个版本中添加,使这些功能更加高效且易于使用。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论