PG訪問外部資料postgres_fdw介紹及示例
postgres fdw是一種外部訪問介面,它可以被用來訪問儲存在外部的資料,這些資料可以是外部的pg資料庫,也可以oracle、mysql等資料庫,甚至可以是檔案。
而本章節主要介紹 postgres_fdw, postgres_fdw 專門為同構資料庫例項提供的外部封裝訪問擴充套件應用。
該模組提供的功能與舊dblink模組的功能基本重疊。但是postgres_fdw
為訪問遠端表提供了更透明和符合標準的語法,並且在許多情況下可以提供更好的效能。而我們的PostgreSQL 內建sharding 也將是基於postgres_fdw實現。
使用postgres_fdw產要有以下步驟:
- 建立擴充套件
- 建立服務
- 建立使用者對映
- 建立與訪問表對應的外表
到此就可以使用SELECT從外部表中訪問儲存在其底層遠端表中的資料。同時可以 UPDATE,INSERT,DELETE遠端表資料庫,前提是在使用者對映中指定的遠端使用者必須具有執行這些操作的許可權。
更多支援可以參考: https://wiki.postgresql.org/wiki/Foreign_data_wrappers
1. 安裝使用
這裡建立2個數據庫db01,db02,2個使用者user01,user02分別用來作為本地和遠端的資料庫和使用者。
1.1 初始化資料
#實始化user01,db01 和 user02,db02 create user user01 superuser password 'user01'; create database db01 owner=user01 TEMPLATE=template0 LC_CTYPE='zh_CN.UTF-8'; create user user02 superuser password 'user02'; create database db02 with owner=user02 TEMPLATE=template0 LC_CTYPE='zh_CN.UTF-8'; #在db02下建立表 \c db02 user02 create table table1 (id int, crt_Time timestamp, info text, c1 int); create table table2 (id int, crt_Time timestamp, info text, c1 int); insert into table1 select generate_series(1,1000000), clock_timestamp(), md5(random()::text), random()*1000; insert into table2 select generate_series(1,1000000), clock_timestamp(), md5(random()::text), random()*1000;
1.2 安裝fdw
1.2.1安裝
postgres@s2ahumysqlpg01-> psql
psql (12.4)
Type "help" for help.
postgres=# \c db01 user01 ;
Password for user user01:
You are now connected to database "db01" as user "user01".
db01=# create extension postgres_fdw;
CREATE EXTENSION
1.2.2 檢視系統表
通過下列系統表可以檢視資料庫外部表資訊。
| 系統表 | 簡命令操作 | 含義 | |:-----:-----:-----:-----:----| | pg_extension | \dx | 外掛 | | pg_foreign_data_wrapper | \dew | 支援外部資料庫介面 | | pg_foreign_server | \des | 外部伺服器 | | pg_user_mappings | \deu | 使用者管理 | | pg_foreign_table | \det | 外部表 | # 示例: postgres=# \deu List of user mappings Server | User name --------+----------- (0 rows) postgres=# \det List of foreign tables Schema | Table | Server --------+-------+-------- (0 rows)
1.3 建立服務
db01=# CREATE SERVER db02
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '192.168.1.55', port '5432', dbname 'db02');
CREATE SERVER
db01=#
db01=# select * from pg_foreign_server ;
oid | srvname | srvowner | srvfdw | srvtype | srvversion | srvacl | srvoptions
-------+---------+----------+--------+---------+------------+--------+-------------------------------------------
42887 | db02 | 42860 | 42885 | | | | {host=192.168.1.55,port=5432,dbname=db02}
(1 row)
1.4 建立使用者對映
# 建立使用者user01 與 遠端使用者user02的對映
db01=# CREATE USER MAPPING
FOR user01
server db02
options(user 'user02',password 'user02');
CREATE USER MAPPING
db01=# select * from pg_user_mappings ;
umid | srvid | srvname | umuser | usename | umoptions
-------+-------+---------+--------+----------+-------------------------------
42892 | 42887 | db02 | 42860 | user01 | {user=user02,password=user02}
(1 row)
1.5 建立外來鍵表
#方法一:批量匯入,這種比較常見,可以一次匯入一個模式下的所有表
db01=# import foreign schema public from server db02 into public;
IMPORT FOREIGN SCHEMA
db01=# \det
List of foreign tables
Schema | Table | Server
--------+------------+-------
public | table1 | db02
public | table2 | db02
(2 rows)
# 或者指定表匯入
IMPORT FOREIGN SCHEMA public limit to (table1,table2) from server db02 into public;
#方法二:建立單個鍵表
#先刪除外來鍵表
db01=# DROP FOREIGN TABLE table1,table2 ;
DROP FOREIGN TABLE
#單個表對映
db01=# CREATE FOREIGN TABLE table1 ( id int, crt_Time timestamp, info text, c1 int )
SERVER db02
OPTIONS (schema_name 'public', table_name 'table1');
CREATE FOREIGN TABLE
db01=# CREATE FOREIGN TABLE table2 ( id int, crt_Time timestamp, info text, c1 int )
SERVER db02
OPTIONS (schema_name 'public', table_name 'table2');
CREATE FOREIGN TABLE
db01=# \d
List of foreign tables
Schema | Table | Server
--------+------------+-------
public | table1 | db02
public | table2 | db02
(2 rows)
2.使用示例
2.1 查詢操作
db01=# select count(*) from table1 ;
count
---------
1000000
(1 row)
db01=# select * from table1 where id < 5 ;
id | crt_time | info | c1
----+----------------------------+----------------------------------+-----
1 | 2022-03-07 10:50:06.823333 | bca78dace57fdc25c752140bf84231cf | 916
2 | 2022-03-07 10:50:06.82347 | 7761db8044710ed9c753124ee2b7f2a8 | 2
3 | 2022-03-07 10:50:06.823482 | 974f5189cc308bb87216e3a695ae7716 | 718
4 | 2022-03-07 10:50:06.823488 | 27adfaf05acd9cf6c9eb11173f3bcbf0 | 863
(4 rows)
-- 和外部表關聯查詢。
db01-# SELECT t1.id, t2.crt_time
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.id
WHERE t1.id < 10;
id | crt_time
----+----------------------------
1 | 2022-03-07 10:50:14.235354
2 | 2022-03-07 10:50:14.235581
3 | 2022-03-07 10:50:14.235601
4 | 2022-03-07 10:50:14.23561
5 | 2022-03-07 10:50:14.235618
6 | 2022-03-07 10:50:14.235627
7 | 2022-03-07 10:50:14.235672
8 | 2022-03-07 10:50:14.235683
9 | 2022-03-07 10:50:14.235692
(9 rows)
2.2 寫操作
postgres_fdw 外部表一開始只支援讀,PostgreSQL9.3 版本開始支援可寫。
寫操作需要保證:1. 對映的使用者對有寫許可權;2. 版本需要9.3 以上
# 刪除示例
db01=# select count(*) from table1 ;
count
---------
1000000
(1 row)
db01=# delete from table1 where id <= 10;
DELETE 10
db01=# select count(*) from table1 ;
count
--------
999990
(1 row)
# 插入
db01=# insert into table1 select generate_series(1,5), clock_timestamp(), md5(random()::text), random()*1000;
INSERT 0 5
db01=# select count(*) from table1 ;
count
--------
999995
(1 row)
# 更改
db01=# select * from table1 where id =5 ;
id | crt_time | info | c1
----+----------------------------+----------------------------------+-----
5 | 2022-03-07 11:28:09.735544 | 0f5d447efe103c8bc83d0980005b7177 | 187
(1 row)
db01=# update table1 set info='ahser.hu' where id =5 ;
UPDATE 1
db01=# select * from table1 where id =5 ;
id | crt_time | info | c1
----+----------------------------+----------+-----
5 | 2022-03-07 11:28:09.735544 | ahser.hu | 187
(1 row)
3.補充
3.1支援聚合下推
PostgreSQL10 增強了postgres_fdw 擴充套件模組的特性,可以將聚合、關聯操作下推到遠端PostgreSQL資料庫進行,而之前的版本是將外部表相應的遠端資料全部取到本地再做聚合,10版本這個心特性大幅度減少了從遠端傳輸到本地庫的資料量。提升了postgres_fdw外部表上聚合查詢的效能。
db01=# EXPLAIN(ANALYZE on,VERBOSE on) select id,count(*) from table1 where id < 100 group by id;
QUERY PLAN
------------------------------------------------------------------------------------------------------
Foreign Scan (cost=109.75..198.89 rows=200 width=12) (actual time=148.884..148.969 rows=94 loops=1)
Output: id, (count(*))
Relations: Aggregate on (public.table1)
Remote SQL: SELECT id, count(*) FROM public.table1 WHERE ((id < 100)) GROUP BY 1
Planning Time: 0.136 ms
Execution Time: 149.688 ms
(6 rows)
#其中 remote sql: 表示遠端庫上執行的SQL,此SQL為聚合查詢的SQL。聚合是在遠端上執行的。
3.2 FDW在PG14的新功能
1.批入匯入效能提升
INSERT SELECT 語句將 100 萬行從另一個表插入到該表所用的時間如下。postgres_fdw OPTIONS的 batch_size 引數設定為 100。這意味著一次最多向外部伺服器傳送 100 行:
- 沒有 FDW 的本地表:6.1 秒
- 帶 FDW 的遠端表(改進前):125.3 秒
- 帶 FDW 的遠端表(改進後):11.1 秒
2.FDW 外部表介面支援 truncate [only|cascade] ,可能通過truncatable 引數選項控制預設為true
3.遠端更新引數控制 ,預設情況下,所有使用的外部表postgres_fdw
都假定是可更新的 。可能通過updatable引數選項控制預設為true
4.支援並行/非同步 外部掃描,充許一個查詢引用多個外部表,並行執行外部表掃描。選項async_capable,它允許並行計劃和執行外部表掃描。
5.LIMIT TO 子分割槽,如果指定IMPORT FOREIGN SCHEMA … LIMIT TO,則允許postgres_fdw匯入表分割槽。預設情況下postgres_fdw不允許匯入表分割槽,因為可以使用根分割槽訪問資料。如果使用者想要匯入分割槽表分割槽,PostgreSQL 14添加了一個新的選項LIMIT TO指定子分割槽匯入。
6.保持連線,添加了一個新選項keep_connections,以保持連線處於活動狀態,以便後續查詢可以重用它們。預設情況下,此選項處於on狀態,但如果off,則在事務結束時將丟棄連線。
- 如果在關閉這個選項,可以使用 ALTER SERVER youserrvername OPTIONS (keep_connections 'off');
- 開啟使用ALTER SERVER youserrvername options (set keep_connections 'on');
7.活動和有效的連線列表,新增postgres_fdw_get_connections函式以報告開啟的外部服務連線。該函式將開啟的連線名本地會話返回到postgres_fdw的外部服務。它還輸出連線的有效性。
- 查詢從本地會話到外部伺服器建立的所有開啟連線的外部伺服器名稱: SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
- 丟棄從本地會話到外部伺服器建立的所有開啟連線: select postgres_fdw_disconnect_all();
參考:
支援的外部介面:https://wiki.postgresql.org/wiki/Foreign_data_wrappers
FDW例表:https://pgxn.org/tag/fdw/
PostgreSQL分片實現: https://wiki.postgresql.org/wiki/WIP_PostgreSQL_Sharding
官方文件:https://www.postgresql.org/docs/current/postgres-fdw.html
http://postgres-road.blogspot.com/2021/03/faster-bulk-insertion-to-foreign-tables.html
https://www.percona.com/blog/2021/05/27/new-features-in-postgresql-14-bulk-inserts-for-foreign-data-wrappers/
來自為知筆記(Wiz)