本文抄自:
https://mp.weixin.qq.com/s/7XjPa-ZeU8mNCvcIwOTHrA
Foreign Data Wrappers(FDW)提供了一種機制,通過這種機制,可以使用常規SQL查詢訪問PostgreSQL之外的數據。PostgreSQL附帶了“File FDW”和“PostgreSQL FDW”。PostgreSQL FDW可能看起來有悖常理,但它是一個非常有用的功能。這個版本的FDW有一些非常有用的更新。
所以,讓我們開始了解發生了什么變化。
性能特征
如果您已經在使用PostgreSQL FDW,請注意性能的改進
1 – 並行/異步 外部掃描
(允許一個查詢引用多個外部表,並行執行外部表掃描)
當在多台服務器上執行遠程聚合和遠程連接時,可能會造成性能噩夢。現在可以異步並行執行。之前的順序執行非常緩慢,在某些情況下,速度會很慢。為此,添加了一個新的選項async_capable
,它允許並行計划和執行外部表掃描。
創建服務和用戶映射
-- Create foreign server 1.CREATE SERVER postgres_svr1FOREIGN DATA WRAPPER postgres_fdwOPTIONS (host '127.0.0.1', async_capable "true"); -- Create foreign server 2.CREATE SERVER postgres_svr2FOREIGN DATA WRAPPER postgres_fdwOPTIONS (host '127.0.0.1', async_capable "true"); CREATE USER MAPPING FOR vagrantSERVER postgres_svr1OPTIONS (user 'postgres', password 'pass'); CREATE USER MAPPING FOR vagrantSERVER postgres_svr2OPTIONS (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');
看看計划樹,現在你可以在計划樹中看到兩個異步的外部掃描計划。
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批量插入行。)
現在,批量插入功能已添加到FDW中,postgres_fdw現在支持該功能。其他FDW也有機會實現批量插入。你可以在這里看到。
功能特性
1 – 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 – LIMIT TO 子分區
(如果指定IMPORT FOREIGN SCHEMA … LIMIT TO
,則允許postgres_fdw導入表分區。)
postgres_fdw不允許導入表分區,因為可以使用根分區訪問數據。但是,如果用戶想要導入分區表分區,PostgreSQL 14添加了一個新的選項LIMIT TO
。
在遠程計算機上創建一個新schema,並添加一個父表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
的情況下導入schema,只能看到導入的父表。
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_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 – 保持連接
(添加丟棄緩存的連接功能)
添加了一個新選項keep_connections
,以保持連接處於活動狀態,以便后續查詢可以重用它們。默認情況下,此選項處於on
狀態,但如果off
,則在事務結束時將丟棄連接。
關閉這個選項
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
選項為 on
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將重新建立連接。
結論
FDW API很有希望在每個版本中都得到擴展,但PostgreSQL 14提供了一些以用戶為中心的新功能。與性能相關的改進為許多相關用例使用FDW提供了另一個理由。該功能肯定會在接下來的幾個版本中添加,使這些版本更具性能,更易於使用。