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

Vla*_*cea 10 database postgresql session jdbc prepared-statement

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

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

准备语句仅持续当前数据库会话的持续时间.会话结束时,忘记了准备好的语句,因此必须重新创建它才能再次使用.

但是,Markus Winand(SQL Performance Explained的作者)说:

PostgreSQL没有共享查询计划缓存,但它具有用于预准备语句的可选查询计划缓存.这意味着开发人员可以选择使用带有或不带缓存查询计划的预准备语句.但请注意,在准备好的语句关闭时,缓存将被删除.

哪一个是真的?

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

Vla*_*kov 18

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

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

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

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

注意:JDBC规范要求使用?, ?绑定占位符,而服务器希望$1, $2JDBC驱动程序也可以缓存所谓的解析SQL文本.

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

pgjdbc

https://github.com/pgjdbc/pgjdbc

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

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

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. 当使用PREPAREd语句(换句话说,服务器准备的语句)时,客户端不必一次又一次地发送查询文本.它只发送一个简短的查询名称和绑定变量的值.
  2. 从9.2开始,数据库仍尝试重新计算查询的前几次执行.如果查询需要多个计划或者通用计划足够好,它会这样做.最终(如果查询没有参数,则立即),数据库可能会切换到通用计划.

换句话说,PreparedStatement优化JDBC端的查询解析和数据库端的查询规划.

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

PL/pgSQL中的预处理语句

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

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