Postgresql 中文操作指南

15.1. How Parallel Query Works #

当优化器确定并行查询是特定查询最快的执行策略时,它将创建一个包含 GatherGather Merge 节点的查询计划。下面是一个简单的示例:

EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%';
                                     QUERY PLAN
-------------------------------------------------------------------​------------------
 Gather  (cost=1000.00..217018.43 rows=1 width=97)
   Workers Planned: 2
   ->  Parallel Seq Scan on pgbench_accounts  (cost=0.00..216018.33 rows=1 width=97)
         Filter: (filler ~~ '%x%'::text)
(4 rows)

在所有情况下,GatherGather Merge 节点将只有一个子计划,这是将在并行中执行的计划部分。如果 GatherGather Merge 节点位于计划树的最顶部,则整个查询将并行执行。如果它位于计划树中的其他位置,则它下面的计划部分将并行执行。在上面的示例中,该查询仅访问一个表,因此除了 Gather 节点本身之外,只有一个计划节点;由于该计划节点是 Gather 节点的子节点,因此它将并行执行。

Using EXPLAIN,您可以看到规划器选择的工人的数量。当在查询执行过程中到达 Gather 节点时,实现用户会话的进程将请求与规划器选择的工人的数量相等数量的 background worker processes。规划器将考虑使用的后台工人的数量最多限制为 max_parallel_workers_per_gather。在任何时间点可能存在的后台工人的总数同时受到 max_worker_processesmax_parallel_workers 的限制。因此,可以以少量于计划数量的工人,甚至没有工人来运行并行查询。最佳计划可能取决于可用的工人数量,因此这会导致查询性能不佳。如果这种情况经常发生,请考虑增加 max_worker_processesmax_parallel_workers,以便可以同时运行更多工人,或者减少 max_parallel_workers_per_gather,以便规划器请求更少的工人。

为给定的并行查询成功启动的每个后台 worker 进程都将执行计划的并行部分。领导者也将执行计划的该部分,但它还有额外的职责:它还必须读取 worker 生成的所有元组。当计划的并行部分只生成少量的元组时,领导者通常表现得非常像一个额外的 worker,加速了查询执行。相反,当计划的并行部分生成大量的元组时,领导者可能几乎完全忙于读取 worker 生成的元组,并执行 Gather 节点或 Gather Merge 节点上方计划节点所需的任何进一步处理步骤。在这种情况下,领导者将在执行计划的并行部分方面做得很少。

当计划并行部分顶部的节点是 Gather Merge 而不是 Gather 时,它表明执行计划并行部分的每个进程正在以排序顺序生成元组,并且领导者正在执行保序合并。相比之下,Gather 从 worker 按照任何方便的方式读取元组,破坏可能存在的任何排序顺序。