PreparedStatement Cache使用分析

关于数据库部分的SQL预编译缓存,立足于oracle数据库分析

PreparedStatement Cache两个部分

  1. 数据库服务端的PreparedStatement 缓存
  2. 客户端的PreparedStatement缓存

当前讲的是客户端PreparedStatement缓存

使用PreparedStatement的好处,参考此篇

PreparedStatement解读_wliang578的博客-CSDN博客

纠正问题

看到网上的文章,一次sql请求,PreparedStatement比Statement可以减少请求次数

根本没有这回事,请求数据库的次数都是一样的。创建PreparedStatement对象,在客户端创建预编译对象而已,真正请求到数据库是执行的时候。

用wireshark抓包,请求次数是一样的,但用上连接池pscache的比没用上,请求的数据会减少

这里是以orache数据库为例子,tns协议是oracle的自定义。

从图片看来,有pscache的发送给数据库的请求数据减少

无pscache

有pscache

 

 

数据库连接池对PreparedStatement Cache的实现

目前很多的数据库链接池都有实现dbcp,druid等,主流的数据库连接池都有实现。

优缺点

优点

  1. 减少临时创建PreparedStatement对象(这基本不减少耗时)
  2. 不归还PreparedStatement,也就是打开游标,不关闭游标。(可以提高性能)

缺点

  1. 增大项目的内存,引起fullgc(使用内存=链接数*最大的缓存数量*PreparedStatement的大小)

druid对减少这块内存有做优化,如果是用pscache可以用这个数据库链接池。

参考:Oracle数据库下PreparedStatementCache内存问题解决方案 · alibaba/druid Wiki · GitHub阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池 - Oracle数据库下PreparedStatementCache内存问题解决方案 · alibaba/druid Wikihttps://github.com/alibaba/druid/wiki/Oracle%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8BPreparedStatementCache%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88

不适用场景

1  项目分库很多不适用(pscache是跟链接关联的),需考虑内存的情况
2  项目中占位符编写sql不多情况,缓存会用不上。
mysql数据库不要用,mysql的服务端sql的缓存是跟数据库连接关联的,没意义。

注意

  1. 数据库连接池中的PreparedStatement的缓存对象是跟着数据库链接绑定的
  2. 用pscache先要对项目进行分析,是否有这些不使用场景
  3. 在设置缓存的数量时,可以开启druid的sql监控,看下热sql的使用数量,做设置
  4. 关于pscache的命中情况,druid有监控,可以看

代码分析

基于druid连接池分析

创建prepareStatement对象

com.alibaba.druid.pool.DruidPooledConnection#prepareStatement(java.lang.String)

 关闭prepareStatement

只是软关闭,将DruidPooledPreparedStatement对象的状态设置为关闭。而不是实际的关闭

com.alibaba.druid.pool.DruidPooledPreparedStatement#close

com.alibaba.druid.pool.DruidPooledConnection#closePoolableStatement

 

mysql为什么不开启pscache缓存

mysql数据库下不建议开启pscache,下面有详细的论述。

MySQL JDBC为什么都不开启PreparedStatement Cache_xieyu_zy的博客-CSDN博客_pscache同样技术的文章我发现几年前写过一次,^_^:https://blog.csdn.net/xieyuooo/article/details/10732375当时写这篇文章更多偏重于内部的代码实现逻辑来写,可能很多朋友看得更多是云里雾里,不知道对自己有什么帮助,最近也有人在问我为什么我们写代码不开启PS Cache,其实从源码确实可以找到答案,不过我觉得用博客写源码分析可能更多是对我自己有帮助,对...https://blog.csdn.net/xieyuooo/article/details/99877168

理由

  1. MySQL服务端SQL Cache也是Connection级别

用pscache

 

 
  1.  
    Class.forName("com.mysql.jdbc.Driver");
  2.  
    Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/test?useServerPrepStmts=true&cachePrepStmts=true", "root", "root");
  3.  
    String prepareSql = "select * from user_info where firstName = ?";
  4.  
    PreparedStatement preparedStatement = conn.prepareStatement(prepareSql);
  5.  
     
  6.  
    preparedStatement.setString(1, "zhuke");
  7.  
    preparedStatement.execute();
  8.  
    preparedStatement.close();
  9.  
     
  10.  
    preparedStatement = conn.prepareStatement(prepareSql);
  11.  
    preparedStatement.setString(1, "zhuke1");
  12.  
    preparedStatement.execute();
  13.  
    preparedStatement.close();
 
java 运行

使用mysql的预编译对象PrepateStatement时,一定需要设置useServerPrepStmts=true开启服务器预编译功能,设置cachePrepStmts=true开启客户端对预编译对象的缓存。

 

假设不开启(useServerPrepStmts=false)。 使用com.mysql.jdbc.PreparedStatement进行本地SQL拼装, 最后送到db上就是值已经替换了后的终于SQL

引用:JDBC使用PrepareStatement对性能的提升分析 - 简书

mysql预处理和非预处理性能对比

MySQL数据库中预处理prepared statement性能测试的示例 - MySQL数据库 - 亿速云小编给大家分享一下MySQL数据库中预处理prepared statement性能测试的示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇...https://www.yisu.com/zixun/374687.html

相关文章参考

JDBC之PreparedStatement的理解 - 灰信网(软件开发博客聚合)

JDBC preparedStatement和连接池PreparedStatementsCache_花飘万家雪的博客-CSDN博客

Druid源码阅读6-PreparedStatementPool源码及使用场景分析 - 掘金

 

PreparedStatement Cache使用分析_cacheprepstmts-CSDN博客

PreparedStatement解读_preparedstatement占位-CSDN博客

PreparedStatement预编译SQL,参数采用占位符的方式

为什么使用PreparedStatement

  1. 防止SQL注入风险
  2. 批处理,减少对数据库请求,减少程序耗时

PreparedStatement与Statement

两种方式,请求数据库的次数是相同。

Statement在数据库中属于一次编译使用(不使用占位符,不同的sql查询参数值,在数据库层面就是不同的SQL执行,不利用数据库层面的SQL缓存)

SQL耗时简单分析

SQL的耗时只要是在以下方面

  1. 解析SQL,生产执行计划
  2. 取数据

在解析SQL,生产计划,Statement属于一次性的使用。这款的耗时相比是增加的,在批处理的时候更能体现出来。

PreparedStatement多条语句,一次请求,可以用上相同的SQL执行计划,请求的次数减少,耗时也好。

PreparedStatement Cache的性能耗时对比_pscache-CSDN博客

PreparedStatement Cache的分析

PreparedStatement Cache使用分析_wliang578的博客-CSDN博客

性能压测基于oracle数据库的11.2的版本

优化后:增加了pscache。

压测场景:

1 两条简单的查询语句

orm框架:hibernate

数据库连接池:druid

缓存最大的pscache数量:20

从上述的对比来看,增加了pscache耗时还有增加,出乎意料。

从各大线程池(dbcp,druid)提供方,都说增加pscache对性能提升巨大,所以才去尝试。为什么结果会如此的不一样的

猜想

1 对低版本的数据库,可能是有用的(没做测试)。oracle服务端本身是有缓存,对于高频率的语句,也不会很快淘汰。特别是对于oracle这样的付费数据,注重性能,对这块本身会不断优化。

Oracle数据库下PreparedStatementCache内存问题解决方案 · alibaba/druid Wiki · GitHub阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池 - Oracle数据库下PreparedStatementCache内存问题解决方案 · alibaba/druid Wikihttps://github.com/alibaba/druid/wiki/Oracle%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8BPreparedStatementCache%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88

 

此片文章,写于2012年,都过去10年了,技术日新月异,是否还有用?

2 本人压测的场景有问题

综合自己分析,自认为是没问题的,单一的应用,单一的语句。

关于增加pscache耗时增加分析

这块耗时增加也是少量的,压测的量是很大的tps上百,需要的数据库连接会增加,缓存ps对象是要内存的,这块主要是新生代内存回收的时间

总结:通过压测分析,认为目前pscache对于oracle的一些版本,根本没减少耗时。所以建议不开启pscahe

如果有不同的答案,认为测试不合理,结果存疑,欢迎进行指正。

posted @ 2025-08-14 09:52  CharyGao  阅读(34)  评论(0)    收藏  举报