Oracle为了提升数据库访问性能,提供了服务器端缓存和客户端缓存这两种缓存。其中,Oracle客户端缓存可能会使用大量的内存,这是一种有意识的设计选择,在使用大量内存与提升性能之间作出权衡,用内存换取性能。sql
其中主要对内存产生较大影响的缓存有如下几种:数据库
1.查询结果缓存缓存
JDBC驱动缓存中缓存的是sql的执行结果,这样相同sql再次执行时能够直接从缓存中获取数据,而不须要与服务器端交互,从而达到提升查询性能的做用。默认状况下,咱们在使用一个数据库链接去执行查询时,JDBC驱动会为链接内的每个Statement(Statement、PreparedStatement、CallableStatement)建立两个buffer:byte[]和char[]。其中char[]用来保存全部字符类型的行数据,如:CHAR,VARCHAR2,NCHAR等,byte[]用来保存全部的其它类型的行数据。这些buffer在在SQL被解析的时候分配,通常也就是在第一次执行该Statement的时候。Statement会持有这两个buffer,直到它被关闭。服务器
2.PreparedStatement缓存oracle
大型系统中每每不少次执行相同的sql,出于性能方面考虑,驱动重用了PreparedStatement,而不是每次为每条sql建立新的PreparedStatement。JDBC驱动内置了一个语句缓存-- Implicit Statement Cache(它的大小默认为0,即不缓存PreparedStatement)。这个语句缓存对用户是透明的,可经过配置链接属性,设置缓存的PreparedStatement数量。性能
3.buffer缓存fetch
Oracle11.2版本驱动中,驱动程序中提供了一个内存管理更复杂的方法。这个方法有两个目标,最大限度减小内存未使用量和最小化buffer分配带来的成本。驱动程序在每一个链接内部建立了一个buffer缓存(buffer cache)。当一个PreparedStatment使用结束被放回Implicit Statement Cache中时,它的buffer会被缓存到buffer缓存中buffer桶(buncket)中,一个buffer桶中的全部buffer都是相同大小且这个大小是预先肯定的。当一个PreparedStatement是从Implicit Statement中取出时,也同时会从buffer缓存中根据查询结果的大小从适当的buffer桶中取出buffer。优化
驱动提供一个链接属性oracle.jdbc.maxCachedBufferSize。它是一个int字符串,默认是Integer.MAX_VALUE。此属性限定了保存在buffer桶中buffer最大的长度大小。超过这个大小 的buffer会在PreparedStatement被放回Implicit Statement Cache中时释放,小于这个大小的buffer会被缓存到相应的buffer桶中,当PreparedStatement从Implicit Statement Cache中取出时,小于maxCachedBufferSize的buffer会从合适的buffer 桶中取出,大于maxCachedBufferSize的buffer 会被从新建立。spa
buffer是在SQL解析的时候被分配的,buffer的大小并不取决于查询返回的行数据的实际长度,而是行数据可能的最大的长度。在SQL解析时,每列的类型是已知的,从该信息中驱动程序能够计算存储每一列所需的内存的最大长度。驱动程序也有fetchSize属性,也就是每次fetch返回的行数。有了每列有大小和行数的大小,驱动程序能够由此计算出一次fetch所返回的数据最大绝对长度。这也就是所分配的buffer的大小。hibernate
字符数据存储在char[]buffer中。Java中的每一个字符占用两个字节。一个VARCHAR2(10)列将包含最多10个字符,也就是10个Java的字符,也就是每行20个字节。一个VARCHAR2(4000)列将占用每行8K字节。重要的实际上是column的定义大小,而不是实际数据的大小。一个VARCHAR2(4000)可是只包含了NULL的列,仍然须要每行8K字节。buffer是在驱动程序看到的查询结果以前被分配的,所以驱动程序必须分配足够的内存,以应付最大可能的行大小。一个定义为VARCHAR2(4000)的列最多可包含4000个字符。Buffer必须大到足以容纳4000个字符分配,尽管实际的结果数据可能没有那么大。
BFILE,BLOB和CLOB会被存储为locator。Locator可高达4K字节,每一个BFILE,BLOB和CLOB列的byte[]必须有至少每行4K字节。RAW列最多能够包含4K字节。其它类型的则须要不多的字节。一个合理的近似值是假设全部其它类型的列,每行占用22个字节。
假设目前数据库中,每条记录定义:10K,fetchsize:50,PreparedStatementCache:100,链接池max值:30, 链接池个数:2个。在极端状况下,内存占用会达到:2*10K*50*100*30*2=6GB 。
说明如下参数均可以经过-D方式添加到启动sofa容器的启动参数中设置系统属性。
此属性限定了保存在buffer缓存中buffer的最大的长度大小。它是一个int字符串,默认是Integer.MAX_VALUE。超过这个大小 的buffer会在PreparedStatement被放回Implicit Statement Cache中时释放,小于这个大小的buffer会被缓存到相应的buffer桶中,当PreparedStatement从Implicit Statement Cache中取出时,小于maxCachedBufferSize的buffer会从合适的buffer 桶中取出,大于maxCachedBufferSize的buffer 会被从新建立。
默认值:false,默认状况下,buffer缓存中存储在链接中的,即每一个链接都会有本身的缓存。若是在真实业务场景中,咱们存在大量这样的使用场景:在一个处理逻辑中,咱们须要使用多个链接去访问数据库,那么这些链接各自都有本身的缓存。且相对于线程数来讲存在大量空闲数据库链接,因为默认状况下buffer缓存是附属于每一个链接的,空闲链接的结果就是buffer缓存中有不少不会被用到的buffer,会用不少不必的内存。咱们能够把oracle.jdbc.useThreadLocalBufferCache属性设置为true,这样咱们可让业务处理逻辑所在线程内的全部链接共用一个缓存,即把buffer存储到线程中,如此一来,线程内使用到的链接都会共用当前线程内的buffer。该属性能够经过-D设置System property或者经过的调用getConnection时的connection property。
LOB字段默认大小为4000bytes。设置BLOB字段每次获取字节数据的大小,这种方式也能够限制一行查询结果的大小。因sofa底层使用的是hibernate,不支持对该参数的设置控制。在使用jdbc方式时能够设置该参数。
buffer的大小不是由查询的实际行数决定的,而是由每次获取的行数决定的。这个每次获取的行数也就是fetchSize,见下图。
JDBC驱动默认是10。咱们能够在hibernate_properties_config.xml中经过配置
<prop key="hibernate.jdbc.fetch_size">50</prop>来设置。
或在链接池中按不一样链接池的属性去配置fetchSize大小。
buffer默认是存储在每一个数据库链接中的。链接池中配置太多的链接,会致使链接大部分空闲。在极端状况下,若是链接池内的链接被所有使用,每一个链接内都会有查询结果缓存,就会致使应用程序内存占用暴增。