PostgreSQL中的并行查询

1.并行查询介绍

当优化器判断对于某一个特定的查询,并行查询是最快的执行策略时,优化器将创建一个查询计划。该计划包括一个Gather或Gather Merge节点。举例如下:

postgres=# explain select * from test02 where id < 1000;
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Gather  (cost=1000.00..92399.20 rows=1000 width=4)
   Workers Planned: 2
   ->  Parallel Seq Scan on test02  (cost=0.00..91299.20 rows=417 width=4)
         Filter: (id < 1000)
(4 rows)

在所有的情形下,Gather或Gather Merge 节点都只有一个子计划,它是将被并行执行的计划的一部分。如果 Gather 或Gather Merge节点位于计划树的最顶层,那么整个查询将并行执行。 
在EXPLAIN命令的结果中, 可以看到规划器选择的工作者数量,例如示例中计划的工作者数量为2。 当查询执行期间到达Gather节点时, 实现用户会话的进程将会请求和规划器选择的工作者数量一样多的后台工作者进程 。任何情况下能够存在的后台工作者进程的总数由max_worker_processes和max_parallel_workers进行限制,因此一个并行查询可能会使用比规划中数量要少的工作者来运行, 甚至有可能根本不使用工作者。
2.并行查询应用场景

为了让并行查询计划能够被生成,必须配置好下列设置:
1) max_parallel_workers_per_gather必须被设置为大于零的值。正常情况下,使用的原则是所用的工作者数量不能超过max_parallel_workers_per_gather所配置的数量。
2) dynamic_shared_memory_type必须被设置为除none之外的值。并行查询要求动态共享内存以便在合作的进程之间传递数据。系统一定不能运行在单用户模式下。因为在单用户模式下,整个数据库系统运行在单个进程中,没有后台工作者进程可用。
如果存在以下任意一种情况,规划器不会为一个给定的查询产生并行查询计划:
1) 查询要写任何数据或者锁定任何数据库行。如果一个查询在顶层或者 CTE 中包含了数据修改操作,那么不会为该查询产生并行计划。
2) 查询可能在执行过程中被暂停。只要在系统认为可能发生部分或者增量式执行,就不会产生并行计划。
3) 使用了任何被标记为PARALLEL UNSAFE的函数的查询。
4) 该查询运行在另一个已经存在的并行查询内部。
5) 事务隔离级别是可串行化。
如果存在以下任意一种情况,即使对于一个特定的查询已经产生了并行查询计划,在一些情况下执行时也不会并行执行该计划:
1) 因为存在后台工作者进程的总数不能超过max_worker_processes的限制,导致得不到后台工作者进程。
2) 因为存在为并行查询而启动的后台工作者总数不能超过max_parallel_workers的限制,导致无法获得后台工作者。
3) 客户端发送了一个执行消息,并且消息中要求取元组的数量不为零。
4) 一条准备语句是使用CREATE TABLE .. AS EXECUTE ..语句执行的。 这种结构不适合并行查询。
5) 事务隔离级别是可串行化。这种情况通常不会出现,因为当事务隔离级别是可串行化时不会产生并行查询计划。不过,如果在产生计划之后并且在执行计划之前把事务隔离级别改成可串行化,这种情况就有可能发生。
3.并行计划介绍

目前支持以下类型的并行感知表扫描。
1) 在并行顺序扫描中,表格的块将在协作过程中分配。
2) 在一个并行位图堆扫描中,选择一个进程作为领导者。 该进程执行一个或多个索引的扫描并构建指示需要访问哪些表块的位图。 然后这些块在并行顺序扫描中在协作进程中分配。
3) 在并行索引扫描或并行仅索引的扫描中, 协作进程轮流从索引读取数据。目前, 并行索引扫描仅支持btree索引。
可以使用嵌套循环、 散列连接或合并连接将驱动表连接到一个或多个其他表。
PostgreSQL通过两个阶段的聚合来支持并行聚合。第一阶段中,每个参与查询计划并行部分执行的进程执行一个聚合步骤, 为进程发现的每个分组产生一个部分结果。这在计划中反映为一个 PartialAggregate节点。第二阶段中,部分结果被通过Gather 或Gather Merge节点传输给领导者。最后, 领导者对所有工作者的部分结果进行重聚合以得到最终的结果。 这在计划中反映为一个FinalizeAggregate节点。
如果任何聚合函数调用包含DISTINCT或ORDER BY子句, 则不支持并行聚合,并且对于有序集聚合或者查询涉及GROUPING SETS时也不支持并行聚合。只有当查询中涉及的所有连接也是计划中并行不分的一部分时,才能使用并行聚合。
如果发生想要一个查询能产生并行计划但没有生成的情况时,可以尝试减小parallel_setup_cost或者parallel_tuple_cost。
在执行一个并行计划时,可以用EXPLAIN (ANALYZE,VERBOSE)来显示每个计划节点在每个工作者上的统计信息。例如:

postgres=# explain (analyze,verbose) select * from test02 where id < 1000;
                                QUERY PLAN          
                                                  
--------------------------------------------------------------------------------

 Gather  (cost=1000.00..92399.20 rows=1000 width=4) (actual time=0.308..800.722 
rows=999 loops=1)
   Output: id
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on public.test02  (cost=0.00..91299.20 rows=417 width=4
) (actual time=522.577..788.939 rows=333 loops=3)
         Output: id
         Filter: (test02.id < 1000)
         Rows Removed by Filter: 3333000
         Worker 0: actual time=784.277..784.277 rows=0 loops=1
         Worker 1: actual time=783.410..783.410 rows=0 loops=1
 Planning time: 0.037 ms
 Execution time: 801.359 ms
(12 rows)

4.并行安全性介绍

规划器把查询中涉及的操作分类成并行安全、并行受限 或者并行不安全这三种类型。并行安全的操作不会与并行查询的使用产生冲突。 并行受限的操作不能在并行工作者中执行,但是能够在并行查询的领导者中执行。 因此,并行受限的操作不能出现在Gather或Gather Merge节点之下, 但是能够出现在包含有这样节点的计划的其他位置。并行不安全的操作不能在并行查询中执行,甚至不能在领导者中执行。当一个查询包含任何并行不安全操作时,并行查询对这个查询是完全被禁用的。
下面的操作总是并行受限的:
1) 公共表表达式(CTE)的扫描。
2) 临时表的扫描。
3) 外部表的扫描,除非外部数据包装器有一个IsForeignScanParallelSafe API。
4) 对InitPlan或者相关的SubPlan的访问。
规划器无法自动判定一个用户定义的函数或者聚合是并行安全、并行受限还是并行不安全,除非是被标记出来,所有用户定义的函数都被认为是并行不安全的。在使用CREATE FUNCTION或者ALTER FUNCTION时,可以通过指定PARALLEL SAFE、PARALLEL RESTRICTED或者PARALLEL UNSAFE来设置标记 。在使用CREATE AGGREGATE时,PARALLEL选项可以被指定为SAFE、RESTRICTED或者 UNSAFE。
如果函数和聚合会写数据库、访问序列、改变事务状态或者对设置做持久化的更改,一定要将他们标记为PARALLEL UNSAFE。类似地,如果函数会访问临时表、客户端连接状态、游标、预备语句或者系统无法在工作者之间同步的后端本地状态,必须将他们标记为PARALLEL RESTRICTED。

 

By Kalath

你可能感兴趣的:(PostgreSQL,Highgo,DB)