计划程序将查询中涉及的操作分类为并行安全、并行受限或并行不安全。并行安全操作是指不与并行查询的使用冲突的操作。并行受限操作是指不能在并行工作进程中执行的操作,但可以在并行查询使用时在领导进程中执行。因此,并行受限操作永远不会出现在Gather
或Gather Merge
节点下方,但可以出现在包含此类节点的计划中的其他位置。并行不安全操作是指在并行查询使用时不能执行的操作,即使在领导进程中也不行。当查询包含任何并行不安全内容时,该查询的并行查询将完全禁用。
以下操作始终是并行受限的
公共表表达式 (CTE) 的扫描。
临时表的扫描。
外部表的扫描,除非外部数据包装器具有IsForeignScanParallelSafe
API 指示其他情况。
附加了InitPlan
的计划节点。
引用相关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
节点之上。但是,计划程序不会这样做。
如果您在文档中看到任何不正确的内容、与您对特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。