当前位置: 首页 > 知识库问答 >
问题:

PostgreSQL服务器端准备语句的寿命是多少

曹普松
2023-03-14

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

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

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

哪一个是真的?

只要数据库连接是打开的,那么在使用连接池时,只要池没有显式关闭物理连接,或者一旦JDBC PreparedStatement关闭,服务器端的prepared语句就会被清除,那么该语句就会继续存在。

共有1个答案

喻渊
2023-03-14

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

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

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

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

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

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

https://github.com/pgjdbc/pgjdbc

由于PGJDBC9.4-1202,当使用PreparedStatement时,它会自动缓存服务器端计划。注意:即使close()使用PreparedStatement也会缓存这些语句。为了进入服务器端prepare,您需要执行查询5次(可以通过PrepareThreshold进行配置)。

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

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

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

我不喜欢pgjdbc-ng,但它似乎同时执行解析(默认缓存大小为250个查询)和准备服务器(默认缓存大小为50个查询)。对服务器端准备语句的支持是在2014年2月24日开始的,所以如果您使用的是最近的版本,就可以获得语句缓存。

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

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

关于pgjdbc-ng的性能,我不能说太多,但自从上次我试图向它抛出jmh之后,它以随机异常失败了。

PostgreSQL具有preparedeallocate命令,以便在通过有线发送exec时引用语句。它优化了两个方面:

  1. 当使用prepared语句(换句话说,服务器准备的语句)时,客户端不必一次又一次地发送查询文本。它只发送一个简短的查询名称和绑定变量的值。
  2. 自9.2以来,数据库仍会尝试重新规划查询的前几次执行。它这样做是为了尝试查询是否需要多个计划或者泛型计划是否足够好。最终(如果查询没有参数,则立即),数据库可能切换到通用计划。

换句话说,PreparedStatement既优化了JDBC端的查询解析,又优化了数据库端的查询规划。

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

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

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

 类似资料:
  • 我一直在读一些较新的JDBC连接池(如Tomcat)不支持客户端语句池。我已经读到,这是因为大多数JDBC驱动程序都维护自己的语句缓存。然而,我不认为PostgreSQL会发生这种情况。 我说的对吗?如果是这样,我应该使用一个连接池来缓存准备好的语句,以获得最佳的批插入性能吗? 谢谢

  • 我在准备好的语句中使用了命令,当我在单线程环境中执行它时,它的工作很好,但是在多线程环境中,它会引起一些问题,那就是数据重复,即如果我有5个线程,每个记录会重复5次,我认为db中没有锁来帮助线程。我的代码: 如果employee.size=5,thread count=5,执行后我将得到25条记录,而不是5条

  • 在与甲骨文合作几年后,我刚搬到PostgreSQL。我一直在研究PostgreSQL数据库应用程序(Java、JDBC)中准备语句的一些性能问题。 Oracle在其SGA中缓存准备好的语句-准备好的语句池在数据库连接之间共享。 PostgreSQL文档似乎没有指出这一点。以下是文档中的片段(https://www.postgresql.org/docs/current/static/sql-pre

  • 问题内容: 我在制作启用JDBC的Java应用程序时了解了预备语句,并且我的应用程序使用连接池层,这确保了预备语句在服务器端缓存,这带来了性能上的好处。 但是,对于PHP,我读过的所有内容都表明,它们仅在页面加载期间被缓存。通常,我不会多次重复同一查询,而是在给定的页面加载中运行多个不同的查询,但是会在多个页面加载中重复它们。 由于我的PHP进程是持久性的(即使用PHP- FPM,它们将在整个生命

  • 我正在使用我生成的一个准备好的语句,但在Java抛出的语句上出现了语法错误。然而,当我将PS的toString复制并粘贴到数据库的phpmyadmin中时,它的执行完美无缺。有什么想法会出错吗,我很难理解? 编辑:更改为PS.ExecuteUpdate(查询);还是不起作用。

  • 我读过的一些文章建议由ServiceWorker(WebCacheAPI)缓存的项永远存储在系统中。我遇到过这样一种情况,当用户在很长一段时间后重新访问我的网站时,一些缓存的资源会被自动收回(~ 如果是这种情况,那么浏览器如何决定它必须删除哪些资源?我是否可以告诉浏览器,如果它正在从缓存中删除某些内容,则删除使用相同缓存名称缓存的所有内容?