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