15.1. 并行查询的工作原理#
当优化器确定并行查询是特定查询最快的执行策略时,它将创建一个查询计划,其中包括Gather或Gather 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)
在所有情况下,Gather
或Gather Merge
节点将恰好有一个子计划,该计划是将并行执行的部分。如果Gather
或Gather Merge
节点位于计划树的最顶层,则整个查询将并行执行。如果它位于计划树的其他位置,则只有它下面的计划部分将并行运行。在上面的示例中,查询只访问一个表,因此除了Gather
节点本身之外,只有一个计划节点;由于该计划节点是Gather
节点的子节点,因此它将并行运行。
使用 EXPLAIN,您可以看到计划程序选择的 worker 数量。当在查询执行过程中到达Gather
节点时,实现用户会话的进程将请求一个后台工作进程数量,该数量等于计划程序选择的 worker 数量。计划程序将考虑使用的后台 worker 数量最多限制为max_parallel_workers_per_gather。任何时候可以存在的后台 worker 总数都受max_worker_processes和max_parallel_workers限制。因此,并行查询有可能使用比计划更少的 worker 运行,甚至根本不使用 worker 运行。最佳计划可能取决于可用的 worker 数量,因此这会导致查询性能不佳。如果这种情况经常发生,请考虑增加max_worker_processes
和max_parallel_workers
,以便可以同时运行更多 worker,或者减少max_parallel_workers_per_gather
,以便计划程序请求更少的 worker。
为给定并行查询成功启动的每个后台工作进程都将执行计划的并行部分。领导者还将执行计划的该部分,但它还有额外的责任:它还必须读取 worker 生成的所有元组。当计划的并行部分仅生成少量元组时,领导者通常会非常像一个额外的 worker,从而加快查询执行速度。相反,当计划的并行部分生成大量元组时,领导者可能几乎完全忙于读取 worker 生成的元组,并执行Gather
节点或Gather Merge
节点上方的计划节点所需的任何进一步处理步骤。在这种情况下,领导者将很少执行计划并行部分的工作。
当计划并行部分顶部的节点是Gather Merge
而不是Gather
时,它表示执行计划并行部分的每个进程都在按排序顺序生成元组,并且领导者正在执行保序合并。相比之下,Gather
以方便的任何顺序从 worker 中读取元组,从而破坏可能存在的任何排序顺序。