pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
由于每个工作进程都会将计划的并行部分执行到底,因此不能简单地拿一个普通查询计划并让多个工作进程同时运行。那样每个工作进程都会生成完整输出结果集的一份副本,所以查询不仅不会比平常更快,反而会产生错误结果。相反,计划的并行部分必须是查询优化器内部所说的部分计划;也就是说,它必须被构造为使执行该计划的每个进程只生成输出行的一个子集,并且保证每一条所需输出行都恰好由某个协作进程生成一次。
目前,唯一经过修改以支持并行查询的扫描类型是顺序扫描。因此,并行计划中的 驱动表总是通过Parallel Seq Scan来扫描。关系的块会被分配给 各个协作进程。每次只分配一个块,因此对关系的访问仍然是顺序的。每个进程在 请求新页之前,会先访问分配给它的页上的所有元组。
驱动表可以通过嵌套循环或哈希连接与一个或多个其他表连接。连接的内侧可以是 规划器支持的任何类型的非并行计划,只要它能够安全地在并行工作进程中运行。 例如,内侧可以是这样一个索引扫描:它查找取自连接外侧的值。每个工作进程 都会完整执行连接的内侧,这对哈希连接来说意味着每个工作进程都要构建一个 相同的哈希表。
PostgreSQL 通过分两个阶段进行聚合来支持并行聚合。首先,每个参与查询并行部分的进程执行一个聚合步骤,为该进程所见到的每个分组产生一个部分结果。这在计划中体现为一个 Partial Aggregate 节点。然后,部分结果通过 Gather 节点传送给领导者。最后,领导者会把来自所有工作进程的结果再次聚合,以产生最终结果。这在计划中体现为一个 Finalize Aggregate 节点。
由于 Finalize Aggregate 节点运行在领导者进程上,因此对于那些相对于输入行数会产生较多分组的查询,查询规划器会认为它不太有利。例如,在最坏情况下,Finalize Aggregate 节点看到的分组数可能与所有工作进程在 Partial Aggregate 阶段看到的输入行数一样多。对于这种情况,使用并行聚合显然不会带来性能收益。查询规划器会在规划过程中考虑这一点,因此在这种场景下不太可能选择并行聚合。
并行聚合并非在所有情况下都受支持。每个聚合都必须是并行安全的,并且必须具有合并函数。如果该聚合具有类型为 internal 的转移状态,那么它还必须具有序列化和反序列化函数。更多细节请参见 CREATE AGGREGATE。如果任何聚合函数调用包含 DISTINCT 或 ORDER BY 子句,则不支持并行聚合。对于有序集聚合,或者当查询涉及 GROUPING SETS 时,也不支持并行聚合。只有当查询涉及的所有连接也都属于计划并行部分时,才能使用并行聚合。
如果一个本来预期会生成并行计划的查询却没有生成并行计划,可以尝试降低 parallel_setup_cost 或 parallel_tuple_cost。当然,这样得到的计划可能会比规划器原本偏好的串行计划更慢,但并不总是如此。如果即使把这些设置调得很低(例如都设为零)之后仍然得不到并行计划,那么可能存在某些原因使查询规划器无法为该查询生成并行计划。关于可能的原因,请参见 第 15.2 节 和 第 15.4 节。
在执行并行计划时,可以使用 EXPLAIN (ANALYZE, VERBOSE) 显示每个计划节点的逐工作进程统计信息。这有助于判断工作是否在各个计划节点之间均匀分布,以及更全面地理解该计划的性能特征。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。