mysql开启 pscache_Druid连接池在mysql的场景PS Cache是否需要开启?

看一下,自己项目的druid连接池是否设置了PS Cache。是否需要设置?

1. Druid的相关配置

spring:

datasource:

name: mysql_test

type: com.alibaba.druid.pool.DruidDataSource

#druid相关配置

druid:

#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false。

pool-prepared-statements: true

# max-pool-prepared-statement-per-connection-size: 20

# 或者(只要maxOpenPreparedStatements或者max-pool-prepared-statement-per-connection-size大于0,那么pool-prepared-statements默认true)

maxOpenPreparedStatements: 20

88cbb6eab9ac

image.png

指定了该参数的使用场景。

2. mysql下为什么不推荐使用

使用场景:oracle设为true,mysql设为false。分库分表较多推荐设置为false。

2.1 为什么要做PS Cache

当使用PrepareStatement的时候,同样的SQL语句参数不同时,我们希望客户端或服务端就只需要对SQL语句只解析一次(即只创建一次PreparedStatement对象),这样在一些大并发场景下性能更佳,尤其是互联网高并发的重复SQL场景,解析会占据较大的CPU和时间开销,而本身的执行时间可能占用并不大。

2.2 mysql下的PS Cache

druid会将PrepareStatement对象存储到Map中(LRU缓存,可以通过参数决定缓存的大小)。

存储的源码:com.alibaba.druid.pool.DruidPooledConnection#closePoolableStatement

在closeStatement时,将PrepareStatement对象放入缓存中。

public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException {

PreparedStatement rawStatement = stmt.getRawPreparedStatement();

...

PreparedStatementHolder stmtHolder = stmt.getPreparedStatementHolder();

stmtHolder.decrementInUseCount();

if (stmt.isPooled() && holder.isPoolPreparedStatements() && stmt.exceptionCount == 0) {

//放入缓存

holder.getStatementPool().put(stmtHolder);

stmt.clearResultSet();

holder.removeTrace(stmt);

stmtHolder.setFetchRowPeak(stmt.getFetchRowPeak());

stmt.setClosed(true); // soft set close

} ...

}

查看LRU缓存对象源码:com.alibaba.druid.pool.PreparedStatementPool.LRUCache可以发现,该缓存对象操作不能保证线程安全。

public class LRUCache extends LinkedHashMap {

private static final long serialVersionUID = 1L;

public LRUCache(int maxSize){

super(maxSize, 0.75f, true);

}

protected boolean removeEldestEntry(Entry eldest) {

boolean remove = (size() > dataSource.getMaxPoolPreparedStatementPerConnectionSize());

if (remove) {

closeRemovedStatement(eldest.getValue());

}

return remove;

}

}

druid在存储PreparedStatementHolder时并没有保证线程安全,是因为Connection连接本身是线程安全的。

2.3 mysql以及大量分库分表不推荐使用PS Cache

缓存本质上是空间换取时间。当占用大量空间但缓存命中率低且命中若没有收益,那么就不推荐使用缓存了。

mysql的PS Cache是Connection级别的,当相同的sql被不同的Connection执行时,也不会共享彼此的Connection连接(会在新的Connection重新维护一份)。而执行sql从连接池中获取连接都是无规则的,(同一个会话中开启事务管理器除外),也就是同样的SQL在不同的连接中被使用是十分正常的事情。

即使每个元素在PS Cache占用的内存不多,但因为是Connection级别,当存在大量分库分表的场景下,会产生大量的Connection连接。累积下就会占用大量的内存。

max-pool-prepared-statement-per-connection-size设置的过小,会导致命中率很低,基本没有什么作用。但设置的过大(例如200)会占用大量内存。而且即使命中中了,因为mysql不支持游标,效果不是很好。

综上所述:mysql的druid连接池没必要开启ps cache。

2.4 其他数据库是否开启PS Cache

此处讲述的主要是MySQL及其JDBC的PS Cache的部分问题,在实际的场景中可以作为参考避免一些不必要的问题发生(也未必会遇得到),这些糟点在其他数据库上未必是适用的,例如Oracle在SQL Parser有:Hard Parser和Soft Parser,Soft Parser的就是语法树结果,它存放在Oracle一个单独的共享区域中,并非Session级别,所以不同的Connection之间可以共享同样的SQL语句,Oracle针对所有的SQL语句都会使用LRU算法进行Cache,单从本文提到的PS Cache来讲在Oracle上体现的效果会更好一些。

推荐阅读

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值