PostgreSQL服务器端预处理语句的生命周期是什么

时间:2015-08-30 14:20:04

标签: database postgresql session jdbc prepared-statement

根据PostgreSQL documentation,预准备语句绑定到数据库会话/连接:

  

PREPARE创建一个准备好的声明。准备好的声明是   可用于优化性能的服务器端对象。当。。。的时候   执行PREPARE语句,解析指定的语句,   分析并重写。随后执行EXECUTE命令   已发布,准备好的声明已经计划并执行。

     

预准备语句仅持续当前数据库的持续时间   会话。会话结束时,忘记准备好的声明,   所以必须在重新使用之前重新创建它。

但是,Markus Winand (author of SQL Performance Explained) says that

  

PostgreSQL没有共享查询计划缓存,但它有一个   准备语句的可选查询计划缓存。这意味着   开发人员可以选择使用或不使用预准备语句   缓存的查询计划。但请注意,当缓存被删除时   准备好的声明已经结束。

哪一个是真的?

只要数据库连接处于打开状态,预准备语句是否存在,因此在使用连接池时,只要池没有显式关闭物理连接或者服务器端预处理语句是一旦JDBC PreparedStatement 关闭,就会消失。

2 个答案:

答案 0 :(得分:18)

所以,你的问题最终归结为“java.sql.PreparedStatement如何使用PostgreSQL”。最后请参阅“如何使用服务器准备的计划”的答案。

答案是:这取决于您使用的JDBC驱动程序。

TL; DR :在现代驱动程序中,服务器准备好的语句一直存在,直到连接死亡或语句被另一个语句逐出(常规LRU驱逐)。

注意:PostgreSQL服务器不能跨数据库连接共享预准备语句,因此最好的JDBC驱动程序可以做的是在每个连接中保持计划缓存。

注意:JDBC规范要求对?, ?使用绑定占位符,而服务器需要$1, $2,因此JDBC驱动程序也会缓存所谓的已解析的SQL文本。

有两个众所周知的JDBC驱动程序:pgjdbc和pgjdbc-ng

pgjdbc

https://github.com/pgjdbc/pgjdbc

pgjdbc 9.4-1202起,它在使用PreparedStatement时会自动缓存服务器端计划。 注意:即使您close() PreparedStatement,语句也会被缓存。 为了进入服务器端准备,您需要执行5次查询(可以通过prepareThreshold配置)。

目前,缓存是按连接实现的。默认情况下,pgjdbc缓存256(preparedStatementCacheQueries)个查询和最多preparedStatementCacheSizeMiB个查询。这是一个保守的设置,所以你可能想要调整它。有关属性的说明,请参阅documentation。 缓存包括已解析和服务器准备的语句。​​

github问题:https://github.com/pgjdbc/pgjdbc/pull/319

pgjdbc-NG

https://github.com/impossibl/pgjdbc-ng

我没有进入pgjdbc-ng,但看起来它同时解析(默认缓存大小为250查询)和服务器准备(默认缓存大小为50查询)。服务器端预处理语句的支持于2014年2月24日发布,因此如果您使用稍新的版本,则可以获得语句缓存。

注意:如果您不小心使用了很长的查询,可以点击OutOfMemory,因为pgjdbc-ng不能根据保留的字节数逐出条目。

缓存是每个连接,因此即使您关闭语句也会透明使用。

我不能说pgjdbc-ng性能,但是自从上次我试图抛出jmh以来它随机异常失败了。

github问题:https://github.com/impossibl/pgjdbc-ng/pull/69

服务器准备的计划

PostgreSQL有PREPAREDEALLOCATE命令在通过线路发送EXEC时引用该语句。它优化了两件事:

  1. 使用PREPARE d语句(换句话说,服务器准备的语句)时,客户端不必一次又一次地发送查询文本。它只发送一个简短的查询名称和绑定变量的值。
  2. 从9.2开始,数据库仍尝试重新计算查询的前几次执行。如果查询需要多个计划或者通用计划足够好,它会这样做。最终(如果查询没有参数立即),数据库might switch to a generic plan
  3. 换句话说,PreparedStatement优化了JDBC端的查询解析和数据库端的查询规划。

    此处有更多信息:http://blog.endpoint.com/2014/04/custom-plans-prepared-statements-in.html

    PL / pgSQL

    中的预处理语句

    根据文档,PostgreSQL caches计划在PL / pgSQL中使用查询。这种情况发生在几次执行后(3或5,我不记得确切的阈值),因此在创建存储过程后它可能有点慢,但是它会切换到缓存计划(假设数据库同意使用通用计划)对于特定的查询)。

    换句话说,为了实现“缓存执行计划”,您需要使用最新的JDBC驱动程序,或者可以将所有查询包装到存储过程中。 对程序的调用将在每次执行时重新计算,但是调用本身通常比构成该过程的查询短得多。

答案 1 :(得分:3)

我认为两者都是真的,但毫无疑问,PostgreSQL文档通常比我更真实。但是,在这里我认为PostgreSQL文档可能不准确。

它可能应该是这样的:

  

准备好的语句只能持续到DEALLOCATE且不超过当前数据库会话的持续时间。

在不检查的情况下,我坚信JDBC驱动程序在关闭JDBC PreparedStatement时会释放服务器端预处理语句。