PolarDB PostgreSQL版支持ePQ查看與分析執行計劃。
背景信息
PostgreSQL提供了EXPLAIN
命令用于SQL語句的性能分析,該命令可以輸出SQL對應的查詢計劃,以及在執行過程中的具體耗時、資源消耗等信息,可用于排查SQL的性能瓶頸。
但EXPLAIN
命令只適用于單機執行的SQL性能分析,PolarDB PostgreSQL版的ePQ擴展了EXPLAIN
的功能,使其可以打印ePQ的跨機并行執行計劃,還可以統計ePQ執行計劃在各個算子上的執行時間、數據掃描量、內存使用等信息,并以統一的視角提供給用戶。
前提條件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 11(內核小版本1.1.22及以上)
PostgreSQL 14(內核小版本14.6.6.0及以上)
您可通過如下語句查看PolarDB PostgreSQL版的內核小版本的版本號:
PostgreSQL 11
show polar_version;
PostgreSQL 14
select version();
原理介紹
ePQ查詢的發起進程(QC)與工作進程(Worker)之間采用libpq
的Y
協議進行通信:
QC將
EXPLAIN ANALYZE
命令下發給Worker。各個Worker進程統計本進程內的資源使用、執行耗時等信息。
各個Worker在完成計劃分片的執行后,將統計信息發送給QC。
QC等待所有Worker進程完成各自執行后,進行統計計算并輸出。
功能介紹
執行計劃查看
ePQ的執行計劃是分片的。每個計劃分片(Slice)由計算節點上的虛擬執行單元(Segment)啟動的一組進程(Gang)負責執行,完成SQL的一部分計算。ePQ在執行計劃中引入了Motion算子,用于在執行不同計劃分片的進程組之間進行數據傳遞。因此,Motion算子是計劃分片的邊界。
ePQ中總共引入了三種Motion算子:
PX Coordinator
:源端數據發送到同一個目標端(匯聚)。PX Broadcast
:源端數據發送到每一個目標端(廣播)。PX Hash
:源端數據經過哈希計算后發送到某一個目標端(重分布)。
示例
以下為一個簡單查詢示例:
CREATE TABLE t (id INT); SET polar_enable_px TO ON; EXPLAIN (COSTS OFF) SELECT * FROM t LIMIT 1; QUERY PLAN ------------------------------------------------- Limit -> PX Coordinator 6:1 (slice1; segments: 6) -> Partial Seq Scan on t Optimizer: PolarDB PX Optimizer (4 rows)
以上執行計劃以Motion算子為界,被分為了兩個分片:一個是接收最終結果的分片
slice0
,一個是掃描數據的分片slice1
。對于
slice1
計劃分片,ePQ將使用六個執行單元(segments: 6
)分別啟動一個進程來執行,這六個進程各自負責掃描表的一部分數據(Partial Seq Scan
),通過Motion算子將六個進程的數據匯聚到一個目標端(PX Coordinator 6:1
),傳遞給Limit
算子。如果查詢逐漸復雜,則執行計劃中的計劃分片和Motion算子會越來越多,示例如下:
CREATE TABLE t1 (a INT, b INT, c INT); SET polar_enable_px TO ON; EXPLAIN (COSTS OFF) SELECT SUM(b) FROM t1 GROUP BY a LIMIT 1; QUERY PLAN ------------------------------------------------------------ Limit -> PX Coordinator 6:1 (slice1; segments: 6) -> GroupAggregate Group Key: a -> Sort Sort Key: a -> PX Hash 6:6 (slice2; segments: 6) Hash Key: a -> Partial Seq Scan on t1 Optimizer: PolarDB PX Optimizer (10 rows)
以上執行計劃中總共有三個計劃分片。將會有六個進程(
segments: 6
)負責執行slice2
分片,分別掃描表的一部分數據,然后通過Motion算子(PX Hash 6:6
)將數據重分布到另外六個(segments: 6
)負責執行slice1
分片的進程上,各自完成排序(Sort
)和聚合(GroupAggregate
),最終通過Motion算子(PX Coordinator 6:1
)將數據匯聚到結果分片slice0
。
執行計劃分析
EXPLAIN
中的ANALYZE
選項會使查詢被真正執行,并收集執行過程中的各項統計信息,而不僅僅是打印執行計劃。在ePQ的執行計劃中,同一個算子會被一組進程執行。因此,ePQ的EXPLAIN ANALYZE
需要收集執行同一個算子的所有進程的統計信息。
算子級別的統計信息如下:
算子執行時間:取執行該算子的所有進程的最長執行時間。
算子掃描總行數:取執行該算子的所有進程的掃描行數累加和。
算子執行次數(循環):取執行該算子的所有進程的循環次數累加和。
算子的資源使用信息:取執行該算子的所有進程的資源使用量累加和。
此外,ePQ的EXPLAIN ANALYZE
還可以收集執行同一算子的各進程級別的統計信息,可被用于判斷計劃執行過程中是否存在傾斜。具體包含信息如下:
每個進程的內存使用情況。
每個進程的執行時間。
每個進程的處理行數。
示例
創建一張表并插入數據。
CREATE TABLE t2 (a INT, b INT, c VARCHAR(20)); INSERT INTO t2 SELECT i, i*2, to_char(i, 'FM00000') FROM generate_series(1, 100000) i;
設置如下參數并執行
EXPLAIN ANALYZE
。SET polar_enable_px TO ON; SET polar_px_enable_explain_all_stat TO ON; SET polar_px_explain_memory_verbosity TO detail; EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM t2; QUERY PLAN ------------------------------------------------------------------------------------------- PX Coordinator 6:1 (slice1; segments: 6) (actual time=0.816..54.225 rows=100000 loops=1) Executor Memory: 9kB Workers: 1 Max: 9kB (worker -1) -> Partial Seq Scan on t2 (actual time=0.052..24.732 rows=94720 loops=1) Executor Memory: 326kB Workers: 6 Max: 145kB (worker 1) allstat: worker:0, first_time:7.396(ms), total_time:25(ms), total_num:94720 worker:1, first_time:7.396(ms), total_time:2.819(ms), total_num:5280 worker:2, first_time:7.393(ms), total_time:0.074(ms), total_num:0 worker:3, first_time:7.400(ms), total_time:0.078(ms), total_num:0 worker:4, first_time:7.402(ms), total_time:0.086(ms), total_num:0 worker:5, first_time:7.399(ms), total_time:0.098(ms), total_num:0 Dynamic Pages Per Worker: [512,29] Planning Time: 9.768 ms Optimizer: PolarDB PX Optimizer (slice0) Executor memory: 38K bytes. (slice1) Executor memory: 68K bytes avg x 6 workers, 164K bytes max (seg1). Execution Time: 65.572 ms (17 rows)
在上述執行計劃中:
每個算子下的
Executor Memory
部分打印了執行這個算子的所有進程所使用的總內存量、進程數量以及使用內存量最大的進程編號。allstat
部分打印了執行算子的每一個進程的準備時間(first_time
)、執行時間(total_time
)和處理元組數量(total_num
)。