PolarDB PostgreSQL版的ePQ支持分區表查詢功能。
背景信息
隨著數據量的不斷增長,表的規模將會越來越大。為了方便管理和提高查詢性能,用戶一般會使用分區表,將大表拆分成多張子分區表,每張子分區表又可以進一步拆分成二級子分區表,從而形成了多級分區表。
PolarDB PostgreSQL版支持彈性跨機并行查詢,能夠利用集群中多個計算節點提升只讀查詢的性能。ePQ不僅能夠對普通表進行高效的跨機并行查詢,對分區表也實現了跨機并行查詢。
ePQ對分區表支持的基礎功能如下:
對分區策略為Range/List/Hash的分區表進行并行掃描。
對分區表進行索引掃描。
對分區表進行連接查詢。
此外,ePQ還支持了部分與分區表相關的高級功能:
分區裁剪。
智能分區連接(Partition Wise Join)。
對多級分區表進行并行查詢。
ePQ暫不支持對具有多列分區鍵的分區表進行并行查詢。
前提條件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 11(內核小版本1.1.17及以上)
PostgreSQL 14(內核小版本14.8.11.0及以上)
您可通過如下語句查看PolarDB PostgreSQL版的內核小版本的版本號:
PostgreSQL 11
show polar_version;
PostgreSQL 14
select version();
使用指南
分區表并行查詢
創建一張分區策略為Range的分區表,并創建三個子分區。
CREATE TABLE t1 (id INT) PARTITION BY RANGE(id); CREATE TABLE t1_p1 PARTITION OF t1 FOR VALUES FROM (0) TO (200); CREATE TABLE t1_p2 PARTITION OF t1 FOR VALUES FROM (200) TO (400); CREATE TABLE t1_p3 PARTITION OF t1 FOR VALUES FROM (400) TO (600);
開啟ePQ和ePQ分區表掃描功能。
SET polar_enable_px TO ON; SET polar_px_enable_partition TO ON;
查看對分區表進行全表掃描的執行計劃。
EXPLAIN (COSTS OFF) SELECT * FROM t1; QUERY PLAN ------------------------------------------- PX Coordinator 6:1 (slice1; segments: 6) -> Append -> Partial Seq Scan on t1_p1 -> Partial Seq Scan on t1_p2 -> Partial Seq Scan on t1_p3 Optimizer: PolarDB PX Optimizer (6 rows)
在上述執行計劃中,ePQ將會啟動一組進程并行掃描分區表的每一個子表。每一個掃描進程都會通過
Append
算子依次掃描每一個子表的一部分數據(Partial Seq Scan
),并通過Motion算子(PX Coordinator
)將所有進程的掃描結果匯聚到發起查詢的進程并返回。
分區靜態裁剪
當查詢的過濾條件中包含分區鍵時,ePQ優化器可以根據過濾條件對需要掃描的分區表進行裁剪,避免掃描不需要的子分區,節省系統資源,提升查詢性能。以上述t1
表為例,查看以下查詢的執行計劃。
EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE id < 100;
QUERY PLAN
-------------------------------------------
PX Coordinator 6:1 (slice1; segments: 6)
-> Append
-> Partial Seq Scan on t1_p1
Filter: (id < 100)
Optimizer: PolarDB PX Optimizer
(5 rows)
由于查詢的過濾條件id < 100
包含分區鍵,因此ePQ優化器可以根據分區表的分區邊界,在產生執行計劃時去掉不符合過濾條件的子分區(t1_p2
、t1_p3
),只保留符合過濾條件的子分區(t1_p1
)。
智能分區連接
在進行分區表之間的連接操作時,如果分區策略和邊界相同,并且連接條件為分區鍵時,ePQ優化器可以產生以子分區為單位進行連接的執行計劃,避免兩張分區表進行笛卡爾積式的連接,節省系統資源,提升查詢性能。
以兩張Range分區表的連接為例。
創建兩張分區策略和邊界都相同的分區表
t2
和t3
。CREATE TABLE t2 (id INT) PARTITION BY RANGE(id); CREATE TABLE t2_p1 PARTITION OF t2 FOR VALUES FROM (0) TO (200); CREATE TABLE t2_p2 PARTITION OF t2 FOR VALUES FROM (200) TO (400); CREATE TABLE t2_p3 PARTITION OF t2 FOR VALUES FROM (400) TO (600); CREATE TABLE t3 (id INT) PARTITION BY RANGE(id); CREATE TABLE t3_p1 PARTITION OF t3 FOR VALUES FROM (0) TO (200); CREATE TABLE t3_p2 PARTITION OF t3 FOR VALUES FROM (200) TO (400); CREATE TABLE t3_p3 PARTITION OF t3 FOR VALUES FROM (400) TO (600);
開啟ePQ對分區表的支持。
SET polar_enable_px TO ON; SET polar_px_enable_partition TO ON;
關閉Partition Wise join時,兩表在分區鍵上等值連接的執行計劃如下。
SET polar_px_enable_partitionwise_join TO OFF; EXPLAIN (COSTS OFF) SELECT * FROM t2 JOIN t3 ON t2.id = t3.id; QUERY PLAN ----------------------------------------------------------- PX Coordinator 6:1 (slice1; segments: 6) -> Hash Join Hash Cond: (t2_p1.id = t3_p1.id) -> Append -> Partial Seq Scan on t2_p1 -> Partial Seq Scan on t2_p2 -> Partial Seq Scan on t2_p3 -> Hash -> PX Broadcast 6:6 (slice2; segments: 6) -> Append -> Partial Seq Scan on t3_p1 -> Partial Seq Scan on t3_p2 -> Partial Seq Scan on t3_p3 Optimizer: PolarDB PX Optimizer (14 rows)
從執行計劃中可以看出,執行
slice1
計劃分片的六個進程會分別通過Append
算子依次掃描分區表t2
每一個子分區的一部分數據,并通過Motion算子(PX Broadcast
)接收來自執行slice2
的六個進程廣播的t3
全表數據,在本地完成哈希連接(Hash Join
)后,通過Motion算子(PX Coordinator
)匯聚結果并返回。本質上,分區表t2
的每一行數據都與t3
的每一行數據做了一次連接。開啟Partition Wise join后,再次查看執行計劃。
SET polar_px_enable_partitionwise_join TO ON; EXPLAIN (COSTS OFF) SELECT * FROM t2 JOIN t3 ON t2.id = t3.id; QUERY PLAN ------------------------------------------------ PX Coordinator 6:1 (slice1; segments: 6) -> Append -> Hash Join Hash Cond: (t2_p1.id = t3_p1.id) -> Partial Seq Scan on t2_p1 -> Hash -> Full Seq Scan on t3_p1 -> Hash Join Hash Cond: (t2_p2.id = t3_p2.id) -> Partial Seq Scan on t2_p2 -> Hash -> Full Seq Scan on t3_p2 -> Hash Join Hash Cond: (t2_p3.id = t3_p3.id) -> Partial Seq Scan on t2_p3 -> Hash -> Full Seq Scan on t3_p3 Optimizer: PolarDB PX Optimizer (18 rows)
在上述執行計劃中,執行
slice1
計劃分片的六個進程將通過Append
算子依次掃描分區表t2
每個子分區中的一部分數據,以及分區表t3
相對應子分區的全部數據,將兩份數據進行哈希連接(Hash Join
),最終通過Motion算子(PX Coordinator
)匯聚結果并返回。在上述執行過程中,分區表
t2
的每一個子分區t2_p1
、t2_p2
、t2_p3
分別只與分區表t3
對應的t3_p1
、t3_p2
、t3_p3
做了連接,并沒有與其它不相關的分區連接,提高了效率。
多級分區表并行查詢
在多級分區表中,每級分區表的分區維度(分區鍵)可以不同:例如,一級分區表按照時間維度分區,二級分區表按照地域維度分區。當查詢SQL的過濾條件中包含每一級分區表中的分區鍵時,ePQ優化器支持對多級分區表進行靜態分區裁剪,從而過濾掉不需要被掃描的子分區。
如下圖所示:當查詢過濾條件WHERE date = '202201' AND region = 'beijing'
中包含一級分區鍵date
和二級分區鍵region
時,ePQ優化器能夠裁剪掉所有不相關的分區,產生的執行計劃中只包含符合條件的子分區。由此,執行器只對需要掃描的子分區進行掃描。
示例
創建一張多級分區表。
CREATE TABLE r1 (a INT, b TIMESTAMP) PARTITION BY RANGE (b); CREATE TABLE r1_p1 PARTITION OF r1 FOR VALUES FROM ('2000-01-01') TO ('2010-01-01') PARTITION BY RANGE (a); CREATE TABLE r1_p1_p1 PARTITION OF r1_p1 FOR VALUES FROM (1) TO (1000000); CREATE TABLE r1_p1_p2 PARTITION OF r1_p1 FOR VALUES FROM (1000000) TO (2000000); CREATE TABLE r1_p2 PARTITION OF r1 FOR VALUES FROM ('2010-01-01') TO ('2020-01-01') PARTITION BY RANGE (a); CREATE TABLE r1_p2_p1 PARTITION OF r1_p2 FOR VALUES FROM (1) TO (1000000); CREATE TABLE r1_p2_p2 PARTITION OF r1_p2 FOR VALUES FROM (1000000) TO (2000000);
開啟ePQ對分區表的支持。
SET polar_enable_px TO ON; SET polar_px_enable_partition TO ON;
執行一條以兩級分區鍵作為過濾條件的SQL,并關閉ePQ的多級分區掃描功能,得到PostgreSQL內置優化器經過多級分區靜態裁剪后的執行計劃。
SET polar_px_optimizer_multilevel_partitioning TO OFF; EXPLAIN (COSTS OFF) SELECT * FROM r1 WHERE a < 1000000 AND b < '2009-01-01 00:00:00'; QUERY PLAN ---------------------------------------------------------------------------------------- Seq Scan on r1_p1_p1 r1 Filter: ((a < 1000000) AND (b < '2009-01-01 00:00:00'::timestamp without time zone)) (2 rows)
開啟ePQ的多級分區掃描功能,再次查看執行計劃。
SET polar_px_optimizer_multilevel_partitioning TO ON; EXPLAIN (COSTS OFF) SELECT * FROM r1 WHERE a < 1000000 AND b < '2009-01-01 00:00:00'; QUERY PLAN ---------------------------------------------------------------------------------------------------- PX Coordinator 6:1 (slice1; segments: 6) -> Append -> Partial Seq Scan on r1_p1_p1 Filter: ((a < 1000000) AND (b < '2009-01-01 00:00:00'::timestamp without time zone)) Optimizer: PolarDB PX Optimizer (5 rows)
在上述計劃中,ePQ優化器進行了對多級分區表的靜態裁剪。執行
slice1
計劃分片的六個進程只需對符合過濾條件的子分區r1_p1_p1
進行并行掃描(Partial Seq Scan
),并將掃描到的數據通過Motion算子(PX Coordinator
)匯聚并返回。