我一直在阅读一些新的JDBC连接池(如Tomcat)不支持客户端语句池。我已经读过这是因为大多数JDBC驱动程序都维护自己的语句缓存。但是,我没有看到PostgreSQL发生这种情况。PostgreSQL和JDBC Prepared Statement Caching
我正确吗?如果是这样,我应该使用连接池,可以缓存准备好的语句,以获得最佳的批量插入性能?
感谢
我一直在阅读一些新的JDBC连接池(如Tomcat)不支持客户端语句池。我已经读过这是因为大多数JDBC驱动程序都维护自己的语句缓存。但是,我没有看到PostgreSQL发生这种情况。PostgreSQL和JDBC Prepared Statement Caching
我正确吗?如果是这样,我应该使用连接池,可以缓存准备好的语句,以获得最佳的批量插入性能?
感谢
Tomcat的JDBC连接池提供了StatementCache。我不知道如何使用它(使用JPA),但它承诺“在连接上缓存PreparedStatement
和/或CallableStatement
实例。”
但是对于插入批次,您可能不需要重新使用PreparedStatement
:可以使用this example中所示的addBatch
方法。奇怪的是,official documentation表示“这种方法不能在PreparedStatement
或CallableStatement
上调用”。我猜你必须尝试一下才能发现这是否属实,正如Craig Ringer所说:“PgJDBC只是单独发送它们”。
性能:在客户端,服务器和驱动程序/网络流量中出现故障。
数据库服务器通常会了解对连接期望的查询(这也是为什么通过连接池重新使用连接是个好主意)。我相信PostgreSQL数据库服务器会在相同的查询发生5次以上时开始记住来自连接的查询。
如果驱动程序正确处理客户端重新使用的PreparedStatement
,驱动程序可以决定只发送新数据而不是整个查询。这可以对插入语句产生显着的积极性能影响(并且我相信其中包括用于SQL Server的JDBC驱动程序可以执行此操作)。
如果客户端缓存PreparedStatement
(例如,只有在创建它的连接关闭时语句才关闭),它将有助于不会一次又一次地执行相同的代码(也来自驱动程序)。即更少的初始化时间和更少的垃圾收集
作为例如用于替代Tomcat的JDBC连接池:我已经使用Yapool的SimpleQueryCache
(example)与该发射了约15个不同的查询有点服务器组件MySQL数据库(和JDBC驱动程序)。在压力/负载测试期间,我惊讶于池中所需的最大连接数量相对较少,这不会影响小型服务器组件的速度(即连接从池中借用相对较短的时间) 。所以,至少在某些情况下,客户端语句的缓存可以有所作为。
在一个侧面节点上:如果你使用类似Hibernate的东西,Hibernate会为你做很多优化(水下),并且很有可能已经为你完成了(语句)高速缓存。
要获得最佳的批插入性能,您应该使用通过PgConnection访问的“COPY”API。 AFAIK PgJDBC不维护“语句缓存”,我不确定这样的事情是否有效,因为每个会话都有自己独立的一组服务器端准备语句。 PgJDBC的声明批量目前是无用的,顺便说一句,它只是单独发送它们。 –
感谢Craig,不幸的是它并不那么简单。该批处理来自JSON,并使用JPA将其解析为具有各种关系的对象图。很难对各种ID进行分类以创建文件来进行复制。 FWIW,如果您甚至准备了20份准备好的声明,则只需准备一次声明并重复使用它就有相当多的价值。 –