Parallel Query(并行查询)

来自 PostgreSQL wiki
跳转到导航跳转到搜索

注意,本页面最初为 PostgreSQL 版本 9.6 撰写,目前尚未更新。要查找有关并行查询的当前文档,请参阅 https://postgresql.ac.cn/docs/current/parallel-query.html

Parallel Query(并行查询)是 PostgreSQL 9.6 中的一项新特性。它可以显著提高某些查询的速度,尤其是当这些查询扫描大量数据但只向客户端返回几行数据时。涉及聚合的查询(例如 `SELECT COUNT(*) FROM table`)通常就是这种情况。但是,并行查询也有一些重要的限制。此 wiki 页面将尝试阐述在 PostgreSQL 9.6 中可以对并行查询有何种预期。目前,并行性仅用于查询;实用程序命令(例如 `VACUUM` 和 `CLUSTER`)不是查询,因此不会利用并行性。

对于大多数用户而言,要利用并行查询,唯一要做的就是将 `max_parallel_degree` 设置为大于零的值。建议将值设为 1 到 4 之间。应适当考虑 `max_worker_processes` 来设置此数字,它限制了任何时候可以存在的后台工作程序进程的数量。此值不仅包括并行工作程序,还包括可能已配置的任何其他后台工作程序进程。如果生成的查询计划打算使用特定数量的工作程序进程,但在运行时可用的进程少于配置值,那么将使用实际可用的更少数量的工作程序来执行查询。如果根本没有可用的工作程序,则领导者将执行所有工作,既执行计划中计划并行运行的部分,也执行无法并行运行的任何部分。如果所选的并行计划基本上等同于非并行最佳计划,那么这不会造成太大损害,但其他情况下可能效率低下。

何时可以使用并行查询?

max_parallel_degree = 0 时,查询规划器将绝不会生成并行计划。这是一种通用原则的特殊情况 ,即不会使用超出通过 max_parallel_degree 配置的工人数。查询规划器在 dynamic_shared_memory_type = none 情况下也不会生成并行计划, 因为并行查询需要动态共享内存段来在协作进程之间交换数据。此外,由于实现限制,当 transaction_isolation = serializable 时也不会生成并行计划。

即使已通用启用并行查询,当以下任一情况为真时,查询规划器仍然绝不会生成并行计划

  • 查询写入数据。 如果查询在顶级中或在 CTE 内包含数据修改操作,则不会生成该查询的任何并行计划。这是当前实现的一个限制,可能会在未来版本中取消。
  • 查询在执行期间可能会挂起。在系统认为可能会发生部分或增量执行的任何情况下,都不会生成并行计划。例如,使用 DECLARE CURSOR 创建的游标将绝不会使用并行计划。类似地,FOR x IN query LOOP .. END LOOP 形式的 PL/pgsql 循环将绝不会使用并行计划,因为并行查询系统无法验证当并行查询活动时循环中的代码是否安全执行。
  • 该查询使用了任何标记为 PARALLEL UNSAFE 的函数。大多数系统定义函数是 PARALLEL SAFE,但用户定义函数默认标记为 PARALLEL UNSAFE。请参阅下文的“函数标记用于并行安全性”部分。
  • 查询在已经并行的另一个查询内部运行。例如,如果一个并行查询调用的函数自行发出一个 SQL 查询,那么该查询将绝不会使用并行计划。这是当前实现的一个限制,但删除此限制可能不可取,因为它可能导致一个查询使用非常多的进程。
  • 系统正在单用户模式下运行。此情况下不会提供任何后台工作程序。

即使生成了一个并行计划,并行性也可能在运行时不被使用,这是出于以下几个原因。首先,整个系统中的后台工作者数受 max_worker_processes 限制;并行工作者包含在这个总数中。这可能导致某个查询运行时,工作者数量比计划的少,甚至没有工作者。其次,如果使用扩展查询协议提交查询,将根据 Execute 消息将包含提取计数 0 的假设作为计划。如果使用非零提取计数,该计划将没有工作者执行。第三,如果查询计划在除 serializable 以外的事务隔离级别生成,但是事务隔离级别在计划时间与执行时间之间变为 serializable,那么并行计划将没有工作者执行。在并行计划没有工作者执行的任何情况下,整个计划都将由领导者执行,而这可能是低效的。该计划是基于将使用工作者的想法而选择的,并且可能与在认为没有可用工作者时选择的计划不同。

支持哪些类型的并行计划?

通常,一个并行计划将由最多四部分组成,其中两部分是可选的

1. 最内部的路径将是并行顺序扫描。目前,并行查询仅为那些驱动表通过顺序扫描而不是通过索引进行扫描的查询生成路径。Parallel Seq Scan 节点将用于取代通常用于扫描表的 Seq Scan 节点。这将在工作者之间对数据进行分区;每个工作者都将处理表中自己子集的页面。将按一次一页的方式传递页面,因为页面一旦可用就将被递交;在进入下一页之前,每个工作者都会处理一页上的所有元组。

2. 此路径可以使用嵌套循环或哈希连接器连接到其他一个或多个表。连接的外侧可以是计划者支持的任何类型的路径;例如,它可以是基于从内部表中获取的列查找值的索引扫描。每个工作者都将完全执行计划的外侧,这就是这里不支持合并连接的原因。合并连接的外侧通常涉及对整个内部表进行排序;即使它涉及索引,也可能导致多个进程对内部表进行完整的索引扫描,而这是没有生产力的。

3. 可使用分组或哈希聚集联合步骤产生的路径。仅当以下情况发生时,才会进行此操作:(a) 查询实际涉及聚合步骤,(b) 聚合步骤仅涉及标记为PARALLEL SAFE的聚合,(c) 聚合具有组合函数,如果它们使用internal 类型的过渡状态、序列化和反序列化函数,以及 (d) 查询中的所有联合步骤都包含在查询并行部分。

4. 最后,一个Gather节点将显示在该计划中所有并行步骤之上。此操作收集了各个工作单元的元组,并将它们带回 leader,后者可以将它们返回给客户端。

与往常一样,可以使用 SQL 命令EXPLAIN来检查查询的计划。如果应生成并行计划的查询并未执行此操作,则可以通过降低parallel_startup_costparallel_tuple_cost的值来获取并行计划。如果该计划生成了一个并行查询,并且需要更多有关工作如何分布的详细信息,则EXPLAIN (ANALYZE, VERBOSE)将执行该查询并针对每个计划节点显示每个工作单元的统计信息。

哪些部分的查询可以在并行中运行?

由于位于Gather节点上方的计划的任何部分都只能由 leader 执行,因此通常情况下需要尽可能多的计划位于Gather节点下方。但是,目前对于并行执行某些操作存在重大限制。具体而言

  • 公共表表达式的扫描不能出现在Gather下方。
  • 如果将集合返回函数标记为PARALLEL RESTRICTED,则它们不能出现在Gather下方。
  • 如果以下情况成立,则纯表的扫描不能出现在Gather下方:(1) 它们是临时表,或 (2) 表上的任何筛选条件使用标记为PARALLEL RESTRICTED的函数,或 (3) 使用了 TABLESAMPLE 子句并且标记表的函数PARALLEL RESTRICTED
  • 仅当外部数据包装器支持该操作时,外表的扫描才能出现在Gather下方。postgres_fdw不支持此操作,但file_fdw支持。
  • 子查询不能出现在Gather下方。请注意,在某些情况下,查询规划器可能会将子查询“扁平化”到包含查询中,从而避免了此限制。
  • 具有 InitPlans 或 SubPlans 的计划节点不能出现在Gather下方。

并行安全的功能标记

函数和聚合可以标记为PARALLEL UNSAFE(默认)、PARALLEL RESTRICTEDPARALLEL SAFE。当将函数或聚合标记为PARALLEL UNSAFE时,引用该函数的查询永远不会并行运行。标记为PARALLEL RESTRICTED意味着该函数可能存在于并行查询中,但只能存在于在领导者中执行的该查询部分。并行工作进程永远不会被要求执行PARALLEL RESTRICTED函数。PARALLEL SAFE函数可以完全参与并行查询。

如果函数写入数据库、访问序列、更改事务状态(即使是临时,例如建立EXCEPTION块来捕获错误的PL/pgsql函数)或对设置进行持久更改,则必须将其标记为PARALLEL UNSAFE。如果函数访问临时表、客户端连接状态、游标、已准备好的语句或系统无法在并行模式下同步的各种后端本地状态,则必须将函数标记为PARALLEL RESTRICTED。例如,出于最后这个原因,setseedrandom被限制并行。一般来说,如果一个函数在受限制或不安全时被标记为安全,或者如果它在实际上不安全时被标记为受限制,那么在并行查询中使用它时可能会引发错误或产生错误的答案。从理论上讲,如果 C 语言函数被错误地标记,那么它可能会表现出完全未定义的行为,因为系统无法防止任意 C 代码,但是在大多数情况下,结果不会比任何其他函数更糟。如果有疑问,应该将函数标记为UNSAFE,这是默认值。

如果在并行工作进程中执行的函数获取了领导者没有持有的锁,例如通过查询查询中未引用的表,这些锁将在工作进程退出时释放,而不是在事务结束时释放。如果你编写了一个执行此操作的函数,并且这种行为差异对你很重要,请将此类函数标记为PARALLEL RESTRICTED以确保它们只在领导者中执行。