规划器将查询涉及的操作分为“并行安全”、“并行受限”或“并行不安全”。并行安全的操作是指不与并行查询的使用冲突的操作。并行受限的操作是指不能在并行工作进程中执行,但可以在领导进程中执行(当并行查询正在使用时)的操作。因此,并行受限的操作永远不会出现在 Gather
或 Gather Merge
节点下方,但可以出现在包含这些节点的计划的其他地方。并行不安全的操作是指即使在领导进程中也不能在并行查询使用时执行的操作。当查询包含任何并行不安全的操作时,该查询将完全禁用并行查询。
以下操作始终是并行受限的:
公共表表达式 (CTE) 的扫描。
临时表的扫描。
外部表的扫描,除非外部数据包装器具有 IsForeignScanParallelSafe
API 表明情况并非如此。
引用相关 SubPlan
的计划节点。
规划器无法自动确定用户定义的函数或聚合是并行安全、并行受限还是并行不安全,因为这需要预测函数可能执行的每一种操作。通常,这等同于停机问题,因此是不可能的。即使是简单的函数,如果可能的话,我们也尝试过,但这将是昂贵且容易出错的。相反,除非另有标记,否则所有用户定义的函数都假定为并行不安全。在使用 CREATE FUNCTION 或 ALTER FUNCTION 时,可以通过指定适当的 PARALLEL SAFE
、PARALLEL RESTRICTED
或 PARALLEL UNSAFE
来设置标记。在使用 CREATE AGGREGATE 时,可以将 PARALLEL
选项指定为 SAFE
、RESTRICTED
或 UNSAFE
作为相应的值。
如果函数写入数据库、更改事务状态(通过使用子事务进行错误恢复以外的方式)、访问序列或对设置进行持久性更改,则必须将函数和聚合标记为 PARALLEL UNSAFE
。类似地,如果函数访问临时表、客户端连接状态、游标、预备语句或系统无法在工作进程之间同步的各种后端本地状态,则必须将函数标记为 PARALLEL RESTRICTED
。例如,setseed
和 random
就是因为最后这个原因而被标记为并行受限的。
通常,如果一个函数被标记为安全但实际上是受限的或不安全的,或者被标记为受限但实际上是不安全的,那么在并行查询中使用时,它可能会引发错误或产生错误的结果。C 语言函数如果标记不当,理论上可能会表现出完全未定义的行为,因为系统无法保护自己免受任意 C 代码的侵害,但在大多数情况下,结果不会比任何其他函数更糟。如有疑问,最好将函数标记为 UNSAFE
。
如果在并行工作进程中执行的函数获取了领导进程未持有的锁(例如,通过查询查询中未引用的表),则这些锁将在工作进程退出时释放,而不是在事务结束时释放。如果您编写了一个执行此操作的函数,并且这种行为差异对您很重要,请将此类函数标记为 PARALLEL RESTRICTED
,以确保它们仅在领导进程中执行。
请注意,查询规划器不会考虑推迟执行查询中涉及的并行受限函数或聚合,以获得更好的计划。因此,例如,如果应用于特定表的 WHERE
子句是并行受限的,查询规划器将不会考虑在计划的并行部分中执行对该表的扫描。在某些情况下,可以在查询的并行部分中包含对该表的扫描,并将 WHERE
子句的评估推迟到 Gather
节点之上执行(这可能甚至更有效)。但是,规划器不会这样做。
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。