首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为1000个不同的查询创建跨线程共享的prepared语句?

问如何为1000个不同的查询创建跨线程共享的prepared语句?
EN

Stack Overflow用户
提问于 2018-12-08 02:21:28
回答 1查看 607关注 0票数 0

目前,我们有大约1000个查询被执行(根据需要,所有1000个查询不是同时执行的,但一些特定的20个查询以高速率执行),作为生成的任务执行器例程的一部分,通过一些博客我已经开始欣赏使用PreparedStatement,但目前我们不使用相同的。在使用dbcp2作为连接池的同时切换到准备好的语句是否可行?

EN

回答 1

Stack Overflow用户

发布于 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缓存,如下所示:

代码语言:javascript
复制
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);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53674967

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档