文档章节

Oracle JDBC驱动内存

O
 Only_小白
发布于 2017/09/08 09:15
字数 2014
阅读 7
收藏 0

一、JDBC驱动内存机制

       Oracle为了提高数据库访问性能,提供了服务器端缓存和客户端缓存这两种缓存。其中,Oracle客户端缓存可能会使用大量的内存,这是一种有意识的设计选择,在使用大量内存与提高性能之间做出权衡,用内存换取性能。

     其中主要对内存产生较大影响的缓存有以下几种:

     1.查询结果缓存

     JDBC驱动缓存中缓存的是sql的执行结果,这样相同sql再次执行时可以直接从缓存中获取数据,而不需要与服务器端交互,从而达到提高查询性能的作用。默认情况下,我们在使用一个数据库连接去执行查询时,JDBC驱动会为连接内的每一个Statement(Statement、PreparedStatement、CallableStatement)创建两个buffer:byte[]和char[]。其中char[]用来保存所有字符类型的行数据,如:CHAR,VARCHAR2,NCHAR等,byte[]用来保存所有的其它类型的行数据。这些buffer在在SQL被解析的时候分配,一般也就是在第一次执行该Statement的时候。Statement会持有这两个buffer,直到它被关闭。

     2.PreparedStatement缓存

     大型系统中往往很多次执行相同的sql,出于性能方面考虑,驱动重用了PreparedStatement,而不是每次为每条sql创建新的PreparedStatement。JDBC驱动内置了一个语句缓存-- Implicit Statement Cache(它的大小默认为0,即不缓存PreparedStatement)。这个语句缓存对用户是透明的,可通过配置连接属性,设置缓存的PreparedStatement数量。

     3.buffer缓存

     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 会被重新创建。

    

二、内存占用情况

       buffer是在SQL解析的时候被分配的,buffer的大小并不取决于查询返回的行数据的实际长度,而是行数据可能的最大的长度。在SQL解析时,每列的类型是已知的,从该信息中驱动程序可以计算存储每一列所需的内存的最大长度。驱动程序也有fetchSize属性,也就是每次fetch返回的行数。有了每列有大小和行数的大小,驱动程序可以由此计算出一次fetch所返回的数据最大绝对长度。这也就是所分配的buffer的大小。

     字符数据存储在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容器的启动参数中设置系统属性。

 

     1.oracle.jdbc.maxCachedBufferSize

此属性限定了保存在buffer缓存中buffer的最大的长度大小。它是一个int字符串,默认是Integer.MAX_VALUE。超过这个大小 的buffer会在PreparedStatement被放回Implicit Statement Cache中时释放,小于这个大小的buffer会被缓存到相应的buffer桶中,当PreparedStatement从Implicit Statement Cache中取出时,小于maxCachedBufferSize的buffer会从合适的buffer 桶中取出,大于maxCachedBufferSize的buffer 会被重新创建。

     2. oracle.jdbc.useThreadLocalBufferCache

默认值:false,默认情况下,buffer缓存中存储在连接中的,即每个连接都会有自己的缓存。如果在真实业务场景中,我们存在大量这样的使用场景:在一个处理逻辑中,我们需要使用多个连接去访问数据库,那么这些连接各自都有自己的缓存。且相对于线程数来说存在大量空闲数据库连接,由于默认情况下buffer缓存是附属于每个连接的,空闲连接的结果就是buffer缓存中有很多不会被用到的buffer,会用很多没必要的内存。我们可以把oracle.jdbc.useThreadLocalBufferCache属性设置为true,这样我们可以让业务处理逻辑所在线程内的所有连接共用一个缓存,即把buffer存储到线程中,如此一来,线程内使用到的连接都会共用当前线程内的buffer。该属性可以通过-D设置System property或者通过的调用getConnection时的connection property。

    3. OracleStatement.setLobPrefetchSize

              LOB字段默认大小为4000bytes。设置BLOB字段每次获取字节数据的大小,这种方式也可以限制一行查询结果的大小。因sofa底层使用的是hibernate,不支持对该参数的设置控制。在使用jdbc方式时可以设置该参数。

     4.fetchSize

              buffer的大小不是由查询的实际行数决定的,而是由每次获取的行数决定的。这个每次获取的行数也就是fetchSize,见下图。

      

JDBC驱动默认是10。我们可以在hibernate_properties_config.xml中通过配置

   <prop key="hibernate.jdbc.fetch_size">50</prop>来设置。

       或在连接池中按不同连接池的属性去配置fetchSize大小。

5.优化连接池

        buffer默认是存储在每个数据库连接中的。连接池中配置太多的连接,会导致连接大部分空闲。在极端情况下,如果连接池内的连接被全部使用,每个连接内都会有查询结果缓存,就会导致应用程序内存占用暴增。

© 著作权归作者所有

共有 人打赏支持
O
粉丝 2
博文 22
码字总数 11544
作品 0
昌平
私信 提问
Oracle的JDBC驱动的版本你了解吗?

classes12.jar,ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别,之间的差异 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle JDBC驱动来解决的?最常使用的ojdbc14.jar有多...

i33
2012/02/20
0
0
Spring Boot 2.0.3 JDBC整合Oracle 12

整合步骤 1. Oracle驱动引入 Oracle驱动一般不能通过maven仓库直接下载得到,需自行下载并导入到项目的lib目录下,建议通过如下pom依赖引入下载的Oracle驱动 2. POM依赖 3. application.pro...

OSC_fly
07/24
0
0
java连接各种数据库(mysql,sql server,oracle,db2)

MYSQL: private String conUrl ="jdbc:mysql://localhost:3306/数据库"网站推广 Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(conUrl,"用户名","密码"); S......

网络营销
2012/01/09
0
0
JDBC连接各种数据库的字符串

JDBC连接各种数据库的字符串大同小异,在此总结一下,备忘。 oracle driverClass:oracle.jdbc.driver.OracleDriver url:jdbc:oracle:thin:@127.0.0.1:1521:dbname mysql driverClass:com...

长平狐
2012/08/27
858
0
jmeter(八)-JDBC请求(sqlserver)

做JDBC请求,首先要了解这个JDBC对象是什么,然后寻找响应的数据库连接URL和数据库驱动。 数据库URL:jdbc:sqlserver://200.99.197.190:1433;databaseName=ebank 数据库驱动:com.microsoft...

劲风online
2015/01/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

jquery通过id显示隐藏

var $div3 = $('#div3'); 显示 $div3.show(); 隐藏 $div3.hide();

yan_liu
今天
3
0
《乱世佳人》读书笔记及相关感悟3900字

《乱世佳人》读书笔记及相关感悟3900字: 之前一直听「荔枝」,后来不知怎的转向了「喜马拉雅」,一听就是三年。上班的时候听房产,买房了以后听装修,兴之所至时听旅行,分手后听亲密关系,...

原创小博客
今天
3
0
大数据教程(9.6)map端join实现

上一篇文章讲了mapreduce配合实现join,本节博主将讲述在map端的join实现; 一、需求 实现两个“表”的join操作,其中一个表数据量小,一个表很大,这种场景在实际中非常常见,比如“订单日志...

em_aaron
今天
3
0
cookie与session详解

session与cookie是什么? session与cookie属于一种会话控制技术.常用在身份识别,登录验证,数据传输等.举个例子,就像我们去超市买东西结账的时候,我们要拿出我们的会员卡才会获取优惠.这时...

士兵7
今天
3
0
十万个为什么之为什么大家都说dubbo

Dubbo是什么? 使用背景 dubbo为什么这么流行, 为什么大家都这么喜欢用dubbo; 通过了解分布式开发了解到, 为适应访问量暴增,业务拆分后, 子应用部署在多台服务器上,而多台服务器通过可以通过d...

尾生
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部