规划器将查询中涉及的操作归类为 并行安全、并行受限 或 并行不安全。并行安全操作不会与并行查询的使用产生冲突。并行受限操作不能在并行工作进程中执行,但可以在使用并行查询时在领导程序中执行。因此,并行受限操作永远不会出现在 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
节点上方发生此评估。但是,计划程序不会执行此操作。