目前,我们有大约1000个查询被执行(根据需要,所有1000个查询不是同时执行的,但一些特定的20个查询以高速率执行),作为生成的任务执行器例程的一部分,通过一些博客我已经开始欣赏使用PreparedStatement,但目前我们不使用相同的。在使用dbcp2作为连接池的同时切换到准备好的语句是否可行?
发布于 2018-12-08 18:06:18
我已经开始欣赏PreparedStatement的用法了,但目前我们还没有用到同样的用法。
典型的用法是(1)准备一条语句,然后(2)在单个线程中使用它一次或多次。即使您只使用一次,它也可以比常规语句更快。所以一定要试一试。
但是,PreparedStatement并不是要缓存的,因为它的抽象级别太高,无法为所有情况提供最佳性能。数据库驱动程序更适合于以最适合特定数据库引擎的方式优化性能。
如果您关心JDBC性能,我建议您选择HikariCP连接池,它是专门为高性能而设计的。还有一个很好的explanation解释了为什么HikariCP采用不同的语句缓存方法:
驱动程序对给定数据库如何处理准备和执行计划有明确的了解,并且可以更有效地实现缓存。在内存占用和执行速度方面。
考虑到在池级别,池别无选择,只能在每个连接的基础上缓存JDBC PreparedStatement对象。如果用户说他们要缓存250条准备好的语句,而池中有50个连接,那么就有12500个对象。或50000个对象,具有500条语句和100个连接。这还不包括像HashMap条目这样的东西。
现在,以PostgreSQL为例。PostgreSQL使用名为“命名查询”的东西来实现准备好的语句。当您准备语句时,会为其指定一个名称。命名的查询与相关的执行计划一起保存在服务器端。命名查询是全局的,并且在连接之间共享。驱动程序保持SQL字符串的映射以查询名称。
因此,当您调用SQL时,驱动程序会查看是否存在针对给定Connection.prepareStatement()的命名查询。如果是这样,它将在服务器端创建一个新的PreparedStatement对象,该对象通过名称引用查询。
没有PreparedStatement对象保留在内存中或缓存。而且,即使用于准备语句的原始连接已关闭,或者准备是在另一个连接上完成的,它也会正常工作。
这是池无法比拟的效率和性能级别。
我认为,提供语句缓存更有可能伤害其他数据库的用户,而不是帮助。我可以有把握地说,因为从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);https://stackoverflow.com/questions/53674967
复制相似问题