同样技术的文章我发现几年前写过一次,^_^:https://blog.csdn.net/xieyuooo/article/details/10732375
当时写这篇文章更多偏重于内部的代码实现逻辑来写,可能很多朋友看得更多是云里雾里,不知道对自己有什么帮助,最近也有人在问我为什么我们写代码不开启PS Cache,其实从源码确实可以找到答案,不过我觉得用博客写源码分析可能更多是对我自己有帮助,对大家帮助不大,所以我在本文中会尽可能抛开源码本身,从宏观角度来看它在实际的应用场景中问题,让我们在实际应用这些技术的时候可以有更多的参考。
可能有朋友还不清楚PS Cache是什么,这里简单说明一下:当使用PrepareStatement的时候,同样的SQL语句参数不同时,我们希望客户端或服务端就只需要对SQL语句只解析一次(解析SQL语句就是把SQL字符串文本通过“文法、语法”或“文本硬解析”转换为计算机可识别可执行的一种数据结构,这种结构通常是一种树结构,单纯语法级别的树通常叫语法树,达到执行级别还有一些列优化处理和与数据库本身相关的细节包含其中,通常叫执行树,每一种数据库在这些处理逻辑上多少都有一些区别,不过思路上差不多),这样在一些大并发场景下性能更佳,尤其是互联网高并发的重复SQL场景,解析会占据较大的CPU和时间开销,而本身的执行时间可能占用并不大。同时PS本身还可以在一定程度上解决SQL注入问题,启动服务端Cursor默认会启动,另外就MySQL来讲,只有开启了服务端PS Cache才能够使用binary通信协议,否则全部走文本协议,文本协议带来的问题主要就是数据会被放大,在前面的文章中有详细地描述,但MySQL PS Cache本身也有很多的问题,本文就问题本身进行说明,既要用PS Cache又要解这个问题会比较复杂,本文不进行这类探讨。
PS:本文以Java的JDBC连接MySQL数据库是否开启PS Cache来作为讲解,如果是其它语言连接MySQL本文参考价值并不大,只需要看本文最后提到MySQL服务端部分的一些结论即可。
首先来了解下MySQL JDBC中与PS Cache相关的参数和意义:
参数名 | 取值 | 默认值 | 说明 |
cachePrepStmts |
true|false | false | 是否开启ps cache,客户端JDBC生效 |
prepStmtCacheSize |
0~Integer.MAX_VALUE | 25 | 可以Cache的SQL数量,客户端JDBC生效 |
prepStmtCacheSqlLimit |
0~Integer.MAX_VALUE | 256 | SQL的字符数限制,某个SQL超过这个字符数,则不会做Cache ,客户端JDBC生效 |
useServerPrepStmts |
true|false | false | 启动服务端PS Cache,单设置这个参数true不会生效,须同时具备: cachePrepStmts = true prepStmtCacheSize > 0 prepStmtCacheSqlLimit > sql.length() emulateUnsuppor |