codecamp

PostgreSQL 何时会用到并行查询?

有几种设置会导致查询规划器在任何情况下都不生成并行查询计划。为了让并行查询计划能够被生成,必须配置好下列设置。

  • max_parallel_workers_per_gather必须被设置为大于零的值。这是一种特殊情况,更加普遍的原则是所用的工作者数量不能超过max_parallel_workers_per_gather所配置的数量。

此外,系统一定不能运行在单用户模式下。因为在单用户模式下,整个数据库系统运行在单个进程中,没有后台工作者进程可用。

如果下面的任一条件为真,即便对一个给定查询通常可以产生并行查询计划,规划器都不会为它产生并行查询计划:

  • 查询要写任何数据或者锁定任何数据库行。如果一个查询在顶层或者 CTE 中包含了数据修改操作,那么不会为该查询产生并行计划。一种例外是,CREATE TABLE ... ASSELECT INTO以及CREATE MATERIALIZED VIEW这些创建新表并填充它的命令可以使用并行计划。

  • 查询可能在执行过程中被暂停。只要在系统认为可能发生部分或者增量式执行,就不会产生并行计划。例如:用DECLARE CURSOR创建的游标将永远不会使用并行计划。类似地,一个FOR x IN query LOOP .. END LOOP形式的 PL/pgSQL 循环也永远不会使用并行计划,因为当并行查询进行时,并行查询系统无法验证循环中的代码执行起来是安全的。

  • 使用了任何被标记为PARALLEL UNSAFE的函数的查询。大多数系统定义的函数都被标记为PARALLEL SAFE,但是用户定义的函数默认被标记为PARALLEL UNSAFE。参见第 15.4 节中的讨论。

  • 该查询运行在另一个已经存在的并行查询内部。例如,如果一个被并行查询调用的函数自己发出一个 SQL 查询,那么该查询将不会使用并行计划。这是当前实现的一个限制,但是或许不值得移除这个限制,因为它会导致单个查询使用大量的进程。

即使对于一个特定的查询已经产生了并行查询计划,在一些情况下执行时也不会并行执行该计划。如果发生这种情况,那么领导者将会自己执行该计划在Gather节点之下的部分,就好像Gather节点不存在一样。上述情况将在满足下面的任一条件时发生:

  • 因为后台工作者进程的总数不能超过max_worker_processes,导致不能得到后台工作者进程。

  • 由于为并行查询目的启动的后台工作者数量不能超过max_parallel_workers这一限制而不能得到后台工作者。

  • 客户端发送了一个执行消息,并且消息中要求取元组的数量不为零。执行消息可见扩展查询协议中的讨论。因为libpq当前没有提供方法来发送这种消息,所以这种情况只可能发生在不依赖 libpq 的客户端中。如果这种情况经常发生,那在它可能发生的会话中设置 max_parallel_workers_per_gather为零是一个很好的主意,这样可以避免产生连续运行时次优的查询计划。


PostgreSQL 并行查询如何工作
PostgreSQL 并行计划
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

PostgreSQL SQL语言

PostgreSQL 服务器管理

PostgreSQL 客户端接口

PostgreSQL 服务器编程

PostgreSQL 参考

PostgreSQL 内部

PostgreSQL 附录

PostgreSQL 参考书目

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }