如何为将在线程之间共享的1000个不同的查询准备状态?

时间:2018-12-07 18:21:28

标签: spring performance jdbc prepared-statement jdbctemplate

当前,我们产生了大约1000个查询(根据需要,即不是同时执行所有1000个查询,而是以高速率执行某些特定的20个查询),这是生成的任务执行程序执行的例程的一部分,一些博客让我很欣赏PreparedStatement的用法,但是目前我们不使用它。使用dbcp2作为连接池时切换到准备好的语句是否可行?

1 个答案:

答案 0 :(得分:0)

  

我已经开始欣赏PreparedStatement的用法,但是目前我们不使用它。

典型用法是(1)准备一条语句,然后(2)在单线程中使用它一次或多次。即使只使用一次,它也可能比常规语句更快。所以绝对可以尝试一下。

PreparedStatement并不是要缓存的,因为它的抽象级别太高了,无法在所有情况下都提供最佳性能。数据库驱动程序可以更好地以对特定数据库引擎最佳的方式优化性能。

如果您关心JDBC的性能,建议您选择HikariCP连接池,它是专为高性能而设计的。 explanation也有一个很好的原因,说明HikariCP为什么以不同的方式处理语句缓存:

  

驱动程序对给定数据库的处理方式有明确的了解   准备和执行计划,并且可以实现更多缓存   有效率的。在内存占用和执行速度方面。

     

请考虑在池级别上,池别无选择,只能进行缓存   JDBC PreparedStatement对象基于每个连接。如果用户   说他们想缓存250条准备好的语句,并且池中有50条   连接,即12500个对象。或50000个对象,其中500个   语句和100个连接。而且那还没算在内   像HashMap条目一样。

     

现在,以PostgreSQL为例。 PostgreSQL实现   准备的语句称为“命名查询”。当你   准备一条语句,并为其命名。命名查询被保留   服务器端,以及相关的执行计划。命名   查询是全局的,并且在连接之间共享。司机   保留SQL字符串到查询名称的映射。

     

因此,当您致电Connection.prepareStatement()时,驱动程序会   查看是否存在给定SQL的命名查询。如果是这样,它将创建一个   新的PreparedStatement对象,该对象按名称引用了   服务器端。

     

没有PreparedStatement对象保留在内存中或被缓存。而且它   即使用于准备   语句已关闭,或者准备已在另一个Connection上完成。

     

这是池无法达到的效率和性能水平   匹配。

     

我认为提供语句缓存可能会更不利   其他数据库的用户,而不是帮助。我可以这样说   充满信心,因为大量用户从BoneCP切换   或DBCP到HikariCP询问“语句缓存在哪里?!”不带   甚至知道驱动程序固有地支持它。更好。

例如,当使用MySQL时,可以在驱动程序本身中启用PreparedStatement缓存,如下所示:

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/dbname");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);