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

时间:2018-05-08 10:23:57

标签: postgresql prepared-statement connection-pooling npgsql pgbouncer

我的理解是你可以使用预处理语句或连接池(使用像pgPool / pgBouncer这样的工具)和Postgresql,但只能同时受益一个(at least with Npgsql driver for .NET,再加上library author suggests turning off clients-side connection pooling when using PgBouncer) 。我对吗?
如果是这样 - 对于其他运行时和语言,如Java,Python,Go,这是真的吗?或者这是一个特定于实现的问题?

2 个答案:

答案 0 :(得分:2)

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

正如@ laurenz-albe所写,您可以使用pgbouncer和预处理语句,但需要使用会话池。这允许您在连接期间使用预准备语句(即,只要您的NpgsqlConnection实例打开)。但是,如果您处于短暂的连接方案中(例如,为每个HTTP请求打开和关闭连接的Web应用程序),那么您运气不好。从这个意义上讲,可以说汇集和准备的陈述是不兼容的。

但是,如果您使用Npgsql的内部池机制(默认情况下已启用)而不是pgbouncer,那么您准备好的语句将在连接打开/关闭时自动保留。换句话说,当您调用NpgsqlCommand.Prepare()时,如果物理连接恰好已经准备好SQL,那么将重用已准备好的语句。这是专门为解决短期连接方案的预准备语句的速度优势而完成的。这是Npgsql的一个非常独特的行为,see the docs for more info

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

答案 1 :(得分:0)

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

有几种连接池模式:

  • 线程在会话期间(会话池)保留连接:
    在这种情况下,像会话语句这样的持久状态可以在会话期间保持,但是当会话返回到池时,您应该清理状态。

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

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

这取决于您使用的连接池类型。基本上,线程保留连接的时间越长,使用预准备语句就越有意义。

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