Laurenz Albe:JDBC和DBeaver中的PostgreSQL并行查询问题

Laurenz Albe:JDBC和DBeaver中的PostgreSQL并行查询问题

💡 原文英文,约1300词,阅读约需5分钟。
📝

内容提要

本文介绍了DBeaver数据库客户端在与PostgreSQL并行查询连接时的问题,包括并行查询的概念、限制和DBeaver的行为。作者通过重现问题并提供解决方法,总结了DBeaver默认配置中的问题并提出了解决方案。

🔎

延伸解读

DBeaver默认行数限制如何影响并行查询

DBeaver默认使用JDBC的setMaxRows(200)限制结果集大小,这会在执行时向PostgreSQL发送带非零fetch count的Execute消息。根据PostgreSQL文档,这种消息会导致执行器无法启动并行工作进程,即使优化器已计划并行。因此,查询会退化为单线程执行,耗时显著增加。

JDBC与libpq在并行查询上的关键差异

PostgreSQL的并行查询限制中提到,客户端发送带非零fetch count的Execute消息会阻止并行执行,而libpq目前无法发送此类消息,所以问题只出现在不使用libpq的客户端中。DBeaver通过JDBC驱动访问PostgreSQL,恰好触发了这一限制。

调整DBeaver设置以恢复并行处理

要解决此问题,可将DBeaver的行数限制改为0,或在“Data Editor”属性中调整“ResultSet fetch size”。如需永久生效,可在全局设置中修改。这样PostgreSQL就能正常启动并行工作进程,恢复并行查询带来的性能优势。

使用LIMIT替代setMaxRows的优势

如果仍需限制结果集大小,应使用SQL的LIMIT子句而非setMaxRows()。LIMIT在查询规划阶段已知,优化器可据此选择更优计划,且不会阻止并行;而setMaxRows()仅在执行时生效,执行器为安全起见会禁用并行。此外,LIMIT还能让优化器优先快速返回前几行。

❓

Q&A

为什么在DBeaver中执行查询时PostgreSQL没有启动并行工作进程?

因为DBeaver默认使用JDBC的setMaxRows(int)方法将结果集限制为200行,这会在执行时发送一个带有非零fetch计数的Execute消息,触发了PostgreSQL的一个限制:当客户端发送非零fetch计数时,执行器无法启动并行工作进程。

如何配置DBeaver才能让PostgreSQL使用并行查询?

将DBeaver中的行数限制改为0。可以在“Data Editor”面板中直接修改,或点击行限制左侧的“蓝色花朵”图标打开属性对话框,在“Data Editor”属性中修改“ResultSet fetch size”。若要永久生效,可在右上角的“Global settings”中修改。

使用LIMIT子句和setMaxRows()方法对并行查询有什么不同影响?

LIMIT子句在查询规划时已知,优化器知道LIMIT是在Gather节点之后应用,不影响并行性,因此仍可使用并行工作进程;而setMaxRows()在执行时才知道,执行器为了安全会禁用并行。此外,使用LIMIT还能让优化器选择快速返回前几行的计划。

PostgreSQL并行查询有哪些主要限制?

并行查询的主要限制包括:启动并行工作进程的开销较大;工作进程与后端进程之间需要通过动态共享内存进行进程间通信;max_parallel_workers限制整个数据库集群的并行工作进程总数;max_parallel_workers_per_gather限制单个语句可用的并行工作进程数;此外,某些语句(如大多数数据修改语句)、使用PARALLEL UNSAFE函数的查询或在游标中执行的查询无法使用并行查询。

PostgreSQL的并行查询是如何工作的?

PostgreSQL从9.6版本引入并行查询。当优化器认为并行处理能减少执行时间时,会计划额外的并行工作进程。这些进程由查询执行器创建,仅存在于单个SQL语句执行期间,负责计算中间结果,最终在原始后端进程的Gather节点中收集。Gather节点以下的所有步骤并行执行,以上则单线程执行。

JDBC驱动与libpq在并行查询支持上有何区别?

libpq目前无法发送带有非零fetch计数的Execute消息,因此使用libpq的客户端不会触发该限制。而JDBC驱动使用该特性来实现setMaxRows(int)方法,因此使用JDBC的客户端(如DBeaver)可能因设置行数限制而导致并行查询无法启动。

🏷️

标签

➡️

继续阅读