最佳实践

PolarDB PostgreSQL版支持弹性跨机并行查询 (elastic Parallel Query,简称ePQ),能够高效支持轻量级的分析型查询,满足用户日渐需要的HTAP能力。

简介

当查询使用ePQ特性时,PolarDB PostgreSQL版将通过ePQ优化器,生成能够被多个计算节点并行执行的执行计划。ePQ的执行引擎将在多个计算节点上协调执行该计划,同时利用多个节点的CPU、内存、I/O带宽来扫描、计算数据。

您可以通过GUC参数动态调整参与ePQ并行执行的计算节点 (Scale Out),以及节点上的单机并行度 (Scale Up),从而实现Serverless弹性扩展。

ePQ善于解决复杂、执行时间长的OLAP长查询,不适用于简单、执行时间短的OLTP短查询。对于短查询而言,计算节点之间建立连接、数据交换、销毁连接的开销反而会引发查询性能的回退。PolarDB PostgreSQL版支持根据表的大小或执行计划的代价来控制对查询使用ePQ还是单机执行,从而在查询不同大小的表和执行不同代价的计划时,能够选择性能更好的查询执行方式。

关于更多ePQ的原理介绍和性能数据,请参见PolarDB PostgreSQL版:ePQ架构详解

一键开启ePQ功能

如果当前有张表t1,可以通过以下命令一键开启ePQ功能。如输出所示,如果计划中出现PolarDB PX Optimizer,则说明ePQ已经生效。

SET polar_enable_px = 1;
EXPLAIN SELECT * FROM t1;
                                  QUERY PLAN
-------------------------------------------------------------------------------
 PX Coordinator 6:1  (slice1; segments: 6)  (cost=0.00..431.00 rows=1 width=8)
   ->  Partial Seq Scan on t1  (cost=0.00..431.00 rows=1 width=8)
 Optimizer: PolarDB PX Optimizer
(3 rows)

SELECT * FROM t1;

GUC参数说明

参数

说明

polar_enable_px

用于开启或关闭ePQ功能。取值如下:

  • on:开启ePQ功能。

  • off(默认):关闭ePQ功能。

说明

当参数开启后,查询将会优先进入ePQ优化器中,产生能够被并行执行的计。此外,所有ePQ相关的GUC参数将会开始生效。

polar_px_nodes

用于指定参与ePQ的计算节点名称。默认值为空,表示所有只读节点都参与ePQ并行执行:

如果只想配置特定的只读节点参与ePQ并行执行,可以通过以下方法获取只读节点的名称:

=> CREATE EXTENSION polar_monitor;
CREATE EXTENSION

=> SELECT name,slot_name,type FROM polar_cluster_info WHERE type = 'Replica';
 name  | slot_name |  type
-------+-----------+---------
 node2 | replica1  | Replica
 node3 | replica2  | Replica
(2 rows)

然后将得到的节点名称以逗号分隔,设置polar_px_nodes:

=> SET polar_px_nodes = 'node2,node3';
=> SHOW polar_px_nodes;
 polar_px_nodes
----------------
 node2,node3
(1 row)

polar_px_dop_per_node

用于设置当前会话中每个计算节点上参与ePQ并行执行的工作进程数。默认值为3。

说明

一般最佳实践值是当前节点CPU核数的一半。如果当前节点的CPU负载较高,可以递减该参数,直到CPU占用率不超过 80%。当查询性能不佳时,也可以递增该参数,但不要使CPU占用率超过80%,否则可能会拖慢系统的其它后台进程。

polar_px_max_workers_number

用于设置每个计算节点上最多可以同时存在的ePQ工作进程数量。默认值为30。

说明

如果超出这个限制时,查询将会出错:

ERROR:  over px max workers, already xxx workers, max 30 workers

此时,可以增大该参数,以避免出现类似的报错。如果该参数设置得过大,也有可能会使节点上的进程数量过多,增大了OOM的风险。

polar_px_wait_lock_timeout

用于设置ePQ进程阻塞其它进程的最大时间。默认值为1800000毫秒(半小时)。

ePQ进程通常是只读查询,会对进行查询的表加共享锁。而用户的部分DDL需要对表加排他锁,从而因锁冲突而被ePQ进程阻塞,在阻塞到该参数所指定的毫秒数后,ePQ查询将会被取消,为执行DDL的进程让路。

由于ePQ通常被用于执行较为耗时的分析型查询,因此statement_timeout参数需要根据情况设置为一个合理的响应时间,例如10800000毫秒(三小时)。如果使用默认值0(不限时),则执行ePQ查询的数据库连接可能会因为查询用时较久而长时间无法被使用。

synchronous_commit

用于确保ePQ并行查询的数据一致性。取值如下:

  • on:确保ePQ并行查询的数据一致性。表示数据库提交事务时需要等待WAL日志刷入存储后才能返回成功。

  • off(默认):无法确保ePQ并行查询的数据一致性。

polar_px_min_pg_plan_cost

表示启用ePQ的执行计划代价最小值,取值范围:0~999999999999,默认值为50000。单机执行计划代价低于该阈值的查询将不会使用ePQ。

polar_px_min_table_scan_size

表示启用ePQ的最小表大小,取值范围:0~2147483647,默认值为100 MB。当查询中引用的所有表的大小都低于该阈值时,将不会使用ePQ。

polar_px_force_use

表示是否强制使用ePQ进行查询,取值如下:

on:强制使用ePQ进行查询。

off(默认):不强制使用ePQ进行查询。

最佳实践

允许特定的表使用ePQ

如果只想针对特定表执行ePQ,可以开启polar_px_enable_check_workers参数。同时对需要执行ePQ的表显式设置px_workers选项。

ALTER TABLE t1 SET (px_workers = 1);
说明

px_workers的取值如下:

  • -1:禁止对该表使用ePQ并行执行。

  • 0:默认状态,对该表忽略ePQ并行执行。

  • 1:允许对该表使用ePQ并行执行。

开启ePQ功能

全局级别

在PolarDB控制台上设置polar_enable_px参数on,即可全局启用ePQ功能,无论是OLTP查询还是OLAP查询,都将默认使用ePQ。

使用如下示例查看执行计划。如果计划中出现PolarDB PX Optimizer,则说明ePQ已经生效:

=> EXPLAIN SELECT * FROM t1;
                                  QUERY PLAN
-------------------------------------------------------------------------------
 PX Coordinator 6:1  (slice1; segments: 6)  (cost=0.00..431.00 rows=1 width=8)
   ->  Partial Seq Scan on t1  (cost=0.00..431.00 rows=1 width=8)
 Optimizer: PolarDB PX Optimizer
(3 rows)

会话级别

在会话内设置polar_enable_px参数为ON,使当前会话内的所有查询默认使用ePQ:

SET polar_enable_px = ON;

数据库级别/用户级别

在全局级别或会话级别启用ePQ后,会话内的所有的查询都会优先使用ePQ。从最佳实践的角度来说,ePQ更适用于需要进行大量OLAP负载的长查询,而不适用于OLTP短查询。对于短查询来说,ePQ在计算节点间的建立连接、数据交换、销毁连接的开销将会引发查询性能的回退。

如果在业务设计上需要使用到ePQ,那么可以将业务中的分析型SQL提取出来,使用一个特定的数据库来进行ePQ查询:

ALTER DATABASE ap_database SET polar_enable_px = ON;

或使用某个特定的账户,专门用来执行分析型的SQL:

ALTER ROLE ap_role SET polar_enable_px = ON;

查询级别

如果只想对一个会话内的某几条特定查询(例如,夜间报表业务)使用ePQ,可以借助pg_hint_plan插件,通过SQL Hint对特定查询启用ePQ。为使SQL Hint生效,需要确保pg_hint_plan插件已经被添加到GUC参数shared_preload_libraries中。

在查询前添加/*+ PX() */表示对该查询使用ePQ:

=> /*+ PX() */ EXPLAIN SELECT * FROM t1;
                                    QUERY PLAN
----------------------------------------------------------------------------------
 PX Coordinator 6:1  (slice1; segments: 6)  (cost=0.00..431.03 rows=1000 width=8)
   ->  Partial Seq Scan on t1  (cost=0.00..431.00 rows=167 width=8)
 Optimizer: PolarDB PX Optimizer
(3 rows)

在查询前添加/*+ NoPX() */表示对该查询不使用ePQ:

=> /*+ NoPX() */ EXPLAIN SELECT * FROM t1;
                      QUERY PLAN
------------------------------------------------------
 Seq Scan on t1  (cost=0.00..15.00 rows=1000 width=8)
(1 row)

在查询前添加/*+ PX(N) */表示以N作为单节点并行度使用ePQ。例如,N取值为6

=> /*+ PX(6) */ EXPLAIN SELECT * FROM t1;
                                     QUERY PLAN
------------------------------------------------------------------------------------
 PX Coordinator 12:1  (slice1; segments: 12)  (cost=0.00..431.02 rows=1000 width=8)
   ->  Partial Seq Scan on t1  (cost=0.00..431.00 rows=84 width=8)
 Optimizer: PolarDB PX Optimizer
(3 rows)