Postgresql - 准备好的语句与连接池 - 这是一个权衡吗?

问题描述 投票:0回答:3

据我所知,您可以在 Postgresql 中使用准备好的语句或连接池(使用 pgPool/pgBouncer 等工具),但同时只能从其中之一中受益(至少使用适用于 .NET 的 Npgsql 驱动程序,加上 库作者)建议在使用 PgBouncer 时关闭客户端连接池)。我对吗?
如果是这样 - 对于其他运行时和语言(例如 Java、Python、Go)也是如此吗?或者这是一个特定于实现的问题?

postgresql prepared-statement connection-pooling npgsql pgbouncer
3个回答
5
投票

这是一个复杂的问题,但这里有一些答案。

正如 @laurenz-albe 所写,您可以使用 pgbouncer 和准备好的语句,但需要使用会话池。这允许您在连接期间使用准备好的语句(即只要您的 NpgsqlConnection 实例打开)。但是,如果您处于短暂的连接场景(例如,为每个 HTTP 请求打开和关闭连接的 Web 应用程序),那么您就不走运了。从这个意义上说,我们可以说池化和准备好的语句不兼容。

但是,如果您使用 Npgsql 的内部池机制(默认情况下打开)而不是 pgbouncer,那么您准备好的语句将在连接打开/关闭时自动保留。换句话说,当你调用

NpgsqlCommand.Prepare()
时,如果物理连接恰好已经准备好SQL,那么准备好的语句将被重用。这样做是专门为了释放准备好的语句对于短期连接场景的速度优势。这是 Npgsql 的一个非常独特的行为,请参阅文档以获取更多信息

这是进程内连接池的优点之一,而不是像 pgbouncer 这样的进程外池 - Npgsql 在传递时保留有关物理连接的信息,在本例中是一个包含哪些语句的表已准备好(名称和 SQL)。


0
投票

我认为这是一个通用问题,所以我会给出一个通用答案。哪些方面适用于特定的连接池实现可能会有所不同。

连接池有以下几种模式:

  • 线程在会话期间保留连接(会话池):
    在这种情况下,可以在会话期间保留诸如准备好的语句之类的持久状态,但您应该在会话返回到池时清除状态。

  • 线程在数据库事务(事务池)期间保留连接:
    在这种情况下,您必须在每次事务后清理状态,因此准备好的语句没有多大意义。

  • 线程在语句持续时间内保留连接(语句轮询):
    这仅在非常有限的情况下有用,即您不需要跨越多个语句的事务。显然,没有像准备好的语句这样的状态可以共享。

这取决于你使用什么样的连接池。基本上,线程保留连接的时间越长,使用准备好的语句就越有意义。

当然,如果您知道自己在做什么,您也可以在数据库连接建立后立即创建一个准备好的语句,并且永远不要释放它。仅当所有线程需要相同的准备好的语句时,这才有效。这样的设置很容易搞砸。


0
投票

从 PgBouncer 1.21.0 开始,它现在支持事务池模式下名为准备好的语句的协议级别。因此,这不再是一种权衡,您可以同时使用两者。您可以通过在 PgBouncer 的配置文件中将

max_prepared_statements
设置为非零值来打开此支持。有关详细信息,请查看文档:https://www.pgbouncer.org/config.html#max_prepared_statements

© www.soinside.com 2019 - 2024. All rights reserved.