使用ODPS Foreign Table訪問MaxCompute數據
ODPS Foreign Table(ODPS FDW)是云原生數據倉庫 AnalyticDB PostgreSQL 版基于PostgreSQL Foreign Data Wrapper(PG FDW)框架開發的用于訪問MaxCompute外部數據的方案,允許您在云原生數據倉庫 AnalyticDB PostgreSQL 版中創建外表,然后將MaxCompute中的數據通過外表引入云原生數據倉庫 AnalyticDB PostgreSQL 版中進行查詢和分析。
概覽如下圖:
ODPS FDW模塊的加入,填補了當前AnalyticDB PostgreSQL版與MaxCompute的數據同步鏈路的缺失。您通過ODPS FDW可以創建三種類型的ODPS外表。
ODPS非分區外表:映射MaxCompute非分區表。
ODPS末級分區外表:映射MaxCompute末級分區表。
ODPS分區外表:映射MaxCompute分區表。
開始使用ODPS FDW
在AnalyticDB PostgreSQL版數據庫中創建ODPS FDW插件。
CREATE EXTENSION odps_fdw ;
將使用權賦權給所有用戶,示例如下:
GRANT USAGE ON FOREIGN DATA WRAPPER odps_fdw TO PUBLIC;
新建實例默認創建ODPS FDW extension,無需執行創建和賦權操作。
既存實例,可以使用初始賬號,連接指定Database手動執行如下命令,創建ODPS FDW extension。
開始使用ODPS Foreign Table
使用ODPS外表需要以下三要素,缺一不可,包括:
ODPS Server:定義MaxCompute的訪問端點。
ODPS User Mapping:定義MaxCompute的訪問賬戶。
ODPS Foreign Table:定義MaxCompute的訪問對象。
1. 創建ODPS Server
1.1 語法示例
CREATE SERVER odps_serv -- ODPS Server名稱
FOREIGN DATA WRAPPER odps_fdw
OPTIONS (
tunnel_endpoint '<odps tunnel endpoint>' -- ODPS Tunnel Endpoint
);
1.2 參數選項
在AnalyticDB PostgreSQL版中定義ODPS Server只需要指定tunnel_endpoint或odps_endpoint即可。其中:
選項 | 是否必選 | 備注 |
tunnel_endpoint | 可選,優先推薦設置此選項。 | 指 ODPS tunnel 服務的 Endpoint。 |
odps_endpoint | 可選 | 指 MaxCompute 服務的 Endpoint。 |
創建時,可以設置其中任意一個,也可以都設置,優先選擇使用Tunnel Endpoint,當缺少Tunnel Endpoint時,則通過ODPS Endpoint路由到對應的Tunnel Endpoint。
推薦配置阿里云經典網絡或VPC網絡的Tunnel Endpoint,如果使用VPC地址,請確保AnalyticDB PostgreSQL版與ODPS在同一可用區中。
通過配置外網Tunnel Endpoint地址訪問MaxCompute 數據,價格為0.8元/GB。
關于ODPS Endpoint,請參見配置Endpoint。
2. 創建 ODPS User Mapping
2.1 語法示例
CREATE USER MAPPING FOR { username | USER | CURRENT_USER | PUBLIC }
SERVER odps_serv -- ODPS Server 名稱
OPTIONS (
id '<odps access id>', -- ODPS Account ID
key '<odps access key>' -- ODPS Account Key
);
username:映射到外部服務器的現有用戶的名稱。
CURRENT_USER和USER:與當前用戶的名稱匹配。
PUBLIC:包括所有角色,包括以后創建的角色。
2.2 參數選項
在AnalyticDB PostgreSQL版中定義訪問ODPS Server的賬戶,需要指定賬戶類型 TYPE,ID和KEY。
選項 | 是否必選 | 備注 |
| 必選 | 指定賬戶ID。 |
| 必選 | 指定賬戶KEY。 |
3. 創建ODPS Foreign Table
3.1 語法示例
CREATE FOREIGN TABLE IF NOT EXISTS table_name ( -- ODPS 外表名稱
column_name data_type [, ... ]
)
SERVER odps_serv -- ODPS Server 名稱
OPTIONS (
project '<odps project>', -- ODPS 項目空間
table '<odps table>' -- ODPS 表名稱
);
3.2 參數選項
定義了ODPS Server和ODPS User Mapping 后,就可以創建ODPS Foreign Table。參數選項包括:
選項 | 是否必選 | 備注 |
| 必選 | 項目空間。項目空間(Project)是 MaxCompute 的基本組織單元,它類似于傳統數據庫的 Database 或 Schema 的概念,是進行多用戶隔離和訪問控制的主要邊界。詳情請參見項目。 |
| 必選 | MaxCompute表名稱。表是MaxCompute的數據存儲單元,詳情請參見表。 |
| 可選 | 用于定義MaxCompute的末級分區表。分區partition是指在一張表中,根據分區字段(一個或多個字段的組合)對數據存儲進行劃分。也就是說,如果表沒有分區,數據是直接放在表所在的目錄下。如果表有分區,每個分區對應表下的一個目錄,數據是分別存儲在不同的分區目錄下。關于分區的更多介紹請參見分區。 |
3.3 外表分類
根據MaxCompute的表分類,ODPS FDW支持定義以下三種類型的ODPS外表。
非分區外表
非分區ODPS外表映射的是MaxCompute的非分區表。用戶創建外表時,只需要指定有效的project和table屬性即可,無需指定partition屬性或者指定partition屬性為“空”。例如:
CREATE FOREIGN TABLE odps_lineitem ( -- ODPS 外表名稱 l_orderkey bigint, l_partkey bigint, l_suppkey bigint, l_linenumber bigint, l_quantity double precision, l_extendedprice double precision, l_discount double precision, l_tax double precision, l_returnflag char(1), l_linestatus char(1), l_shipdate date, l_commitdate date, l_receiptdate date, l_shipinstruct char(25), l_shipmode char(10), l_comment varchar(44) ) SERVER odps_serv -- ODPS Server 名稱 OPTIONS ( project 'odps_fdw', -- ODPS 項目空間 table 'lineitem_big' -- ODPS 表名稱 );
末級分區外表
相對于非分區外表,末級分區外表,映射的是MaxCompute的末級分區表,需要設置正確的partition屬性,多級分區時,末級分區外表只支持末級分區表,即partition屬性需要包含多級分區完整路徑。
舉例說明:在MaxCompute上創建一個二級分區表,如下:
--創建一個二級分區表,以日期為一級分區,地域為二級分區 CREATE TABLE src (key string, value bigint) PARTITIONED BY (pt string,region string);
當您需要在AnalyticDB PostgreSQL版中定義一個末級分區外表,映射 MaxCompute上一級分區為(20170601),二級分區為(hangzhou)的末級分區表時,需要設置 partition為
'pt=20170601,region=hangzhou'
。CREATE FOREIGN TABLE odps_src_20170601_hangzhou ( -- ODPS 外表 key string, value bigint ) SERVER odps_serv -- ODPS Server 名稱 OPTIONS ( project 'odps_fdw', -- ODPS 項目空間 table 'src', -- ODPS 表名稱 partition 'pt=20170601,region=hangzhou' -- 末級分區完整路徑 );
說明分區的partition specification需按照key=value的方式設置;多級分區時,以逗號分隔,且不能包含額外的空格。
不支持映射非末級分區的表。如,不支持僅設置一級分區路徑:
partition 'pt=20170601'
。一定要設置完整的多級分區路徑。如,不支持僅設置末級分區路徑:
partition '
region=hangzhou'
?。
分區外表
MaxCompute分區外表,映射的是MaxCompute的分區表。同樣,以上述MaxCompute二級分區表src 為例,您可以按照如下方法創建對應的分區外表。更多表分區定義。
CREATE FOREIGN TABLE odps_src( -- ODPS 外表名稱 key text, value bigint, pt text, -- ODPS 一級分區鍵 region text -- ODPS 二級分區鍵 ) SERVER odps_serv OPTIONS ( project 'odps_fdw', -- ODPS 項目空間 table 'src' -- ODPS 表名稱 ) PARTITION BY LIST (pt) -- 一級分區以"pt"字段為分區鍵 SUBPARTITION BY LIST (region) -- 二級分區以"region"字段為分區鍵 SUBPARTITION TEMPLATE ( -- 二級分區模板 SUBPARTITION hangzhou VALUES ('hangzhou'), SUBPARTITION shanghai VALUES ('shanghai') ) ( PARTITION "20170601" VALUES ('20170601'), PARTITION "20170602" VALUES ('20170602'));
說明與MaxCompute分區表定義不同,AnalyticDB PostgreSQL版的分區外表定義時:
需要將分區鍵以字段方式定義在其他字段尾部,多級分區時,分區字段定義順序、分區鍵層級、MaxCompute分區表層級三者需保持一致。
分區表定義需要指定分區鍵值,請使用LIST方式分區。
分區外表定義時,不需要指定partition屬性,這是因為partition屬性標記的是末級分區外表,與分區外表在邏輯上沖突。
當出現MaxCompute上不存在的分區外表,查詢外表時,會告警顯示,用戶可以參考本章的3.5節如何刪除子分區外表刪除相應子分區。
3.4 如何添加子分區外表
以上述odps_src分區外表為例。
添加一級子分區,效果如下圖。
-- 添加一級子分區(自動創建二級子分區)
alter table odps_src add partition "20170603" values(20170603);
添加二級子分區,效果如下圖。
-- 添加二級子分區
alter table odps_src alter partition "20170603" add partition "nanjing" values('nanjing');
3.5 如何刪除子分區外表
以上述odps_src分區外表為例。
刪除一級子分區,效果如下圖。
-- 刪除一級子分區(級聯刪除二級子分區)
alter table odps_src drop partition "20170602";
刪除二級子分區
-- 刪除二級子分區
alter table odps_src alter partition "20170601" drop partition "hangzhou";
MaxCompute外表使用場景
MaxCompute外表掃描,實現了AnalyticDB PostgreSQL版的Foreign Scan算子。因此,表查詢的使用方法上,對MaxCompute外表的查詢與對普通表的查詢基本一致。本文以TPC-H Query為例,舉例說明常見的使用場景。
MaxCompute外表查詢分析
TPC-H Query Q1是典型的單表聚集過濾場景,定義odps_lineitem為MaxCompute外表,對其執行Q1查詢。
-- 定義MaxCompute外表odps_lineitem
CREATE FOREIGN TABLE odps_lineitem (
l_orderkey bigint,
l_partkey bigint,
l_suppkey bigint,
l_linenumber bigint,
l_quantity double precision,
l_extendedprice double precision,
l_discount double precision,
l_tax double precision,
l_returnflag CHAR(1),
l_linestatus CHAR(1),
l_shipdate DATE,
l_commitdate DATE,
l_receiptdate DATE,
l_shipinstruct CHAR(25),
l_shipmode CHAR(10),
l_comment VARCHAR(44)
) server odps_serv
options (
project 'odps_fdw', table 'lineitem'
);
-- TPC-H Q1
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
odps_lineitem
where
l_shipdate <= date '1998-12-01' - interval '88' day --(3)
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus;
MaxCompute數據導入本地表
導入數據時,請執行如下步驟:
在AnalyticDB PostgreSQL版中,創建MaxCompute外表。
執行如下操作,并行導入數據。
-- INSERT方式
INSERT INTO <本地目標表> SELECT * FROM <ODPS 外表>;
-- CREATE TABLE AS 方式
CREATE TABLE <本地目標表> AS SELECT * FROM <ODPS 外表>;
示例1:INSERT方式將odps_lineitem數據導入到本地AOCS表。
-- 創建本地AOCS表
CREATE TABLE aocs_lineitem (
l_orderkey bigint,
l_partkey bigint,
l_suppkey bigint,
l_linenumber bigint,
l_quantity double precision,
l_extendedprice double precision,
l_discount double precision,
l_tax double precision,
l_returnflag CHAR(1),
l_linestatus CHAR(1),
l_shipdate DATE,
l_commitdate DATE,
l_receiptdate DATE,
l_shipinstruct CHAR(25),
l_shipmode CHAR(10),
l_comment VARCHAR(44)
) WITH (APPENDONLY=TRUE, ORIENTATION=COLUMN, COMPRESSTYPE=ZSTD, COMPRESSLEVEL=5)
DISTRIBUTED BY (l_orderkey);
-- 將 odps_lineitem 數據導入到 AOCS 本地表
INSERT INTO aocs_lineitem SELECT * FROM odps_lineitem;
示例2:CREATE TABLE AS方式將odps_lineitem導入到本地heap表。
create table heap_lineitem as select * from odps_lineitem distributed by (l_orderkey);
MaxCompute外表與本地表關聯
以TPC-H Query Q19為例,使用本地列存表aocs_lineitem與MaxCompute外表odps_part關聯查詢。
-- TPC-H Q19
select
sum(l_extendedprice* (1 - l_discount)) as revenue
from
aocs_lineitem, -- 本地 AOCS 列存表
odps_part -- ODPS 外表
where
(
p_partkey = l_partkey
and p_brand = 'Brand#32'
and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')
and l_quantity >= 8 and l_quantity <= 8 + 10
and p_size between 1 and 5
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#41'
and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')
and l_quantity >= 15 and l_quantity <= 15 + 10
and p_size between 1 and 10
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#44'
and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')
and l_quantity >= 22 and l_quantity <= 22 + 10
and p_size between 1 and 15
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
);
將AnalyticDB PostgreSQL內表數據寫入MaxCompute
使用示例:將示例2中heap_lineitem表內數據寫到odps_lineitem表。
INSERT INTO odps_lineitem SELECT * FROM heap_lineitem;
MaxCompute外表使用建議
MaxCompute外表通過網絡訪問MaxCompute,其使用瓶頸不僅受限于機器自身資源,還受到MaxCompute Tunnel對外吞吐的網絡帶寬的限制 。因此,建議您:
使用MaxCompute外表的并發數不應超過5個。
在關聯多張MaxCompute外表時,建議先將大表導入本地,然后再和小的外表進行關聯,以提高性能。
對MaxCompute外表的查詢性能受到MaxCompute中小文件數量的影響,若小文件數量過多,將對查詢性能產生負面影響??赏ㄟ^以下命令在MaxCompute中查看小文件的數量并進行小文件合并。若單次合并小文件后仍存在較多小文件,反復執行合并小文件的命令可實現更為理想的合并效果。
在MaxCompute中執行以下命令查看表的文件數。
desc extended <table_name> [partition (<pt_spec>)];
在MaxCompute中執行以下命令合并小文件。
ALTER TABLE <table_name> [partition (<pt_spec>)] MERGE SMALLFILES;
參數說明
table_name:必填。待查看表的名稱。
pt_spec:可選。待查看分區表的指定分區。格式為
(partition_col1 = partition_col_value1, partition_col2 = partition_col_value2, ...)
。
更多信息請參見合并小文件。
MaxCompute外表數據類型
目前MaxCompute數據類型與云原生數據倉庫 AnalyticDB PostgreSQL 版數據類型的對應關系如下,建議按照此類型對照表來定義外表的字段類型。
目前暫不支持MaxCompute中的STRUCT、MAP、ARRAY類型。
MaxCompute數據類型 | 云原生數據倉庫 AnalyticDB PostgreSQL 版數據類型 |
BOOLEAN | BOOL |
TINYINT | INT2 |
SMALLINT | INT2 |
INTEGER | INT4 |
BIGINT | INT8 |
FLOAT | FLOAT4 |
DOUBLE | FLOAT8 |
DECIMAL | NUMBERIC |
BINARY | BYTEA |
VARCHAR(n) | VARCHAR(n) |
CHAR(n) | CHAR(n) |
STRING | TEXT |
DATE | DATE |
DATETIME | TIMESTAMP |
TIMESTAMP | TIMESTAMP |
Array<SMALLINT/INT/BIGINT/BOOLEAN/FLOAT/DOUBLE/TEXT/VARCHAR/TIMESTAMP> (寫入到MaxCompute外表功能暫不支持Array類型)。 | INT2,INT4,INT8,BOOLEAN,FLOAT4,FLOAT8,TEXT,VARCHAR,TIMESTAMP |