摘要:从Oracle10g开始在JDBC驱动中,增加了对执行每个Statement的缓存。目的就是对相同的SQL缓存其查询结果,从而提高查询的性能。这种缓存形式,在服务端做的比较多,但是Oracle是通过JDBC将结果缓存在离应用程序最近的地方(客户端),不知道其他数据库是否有同样的功能。
一、 缓存的意义
为什么要通过Statement来缓存数据,这样做的前提是PreparedStatement或者是CallableStatement而不是Statement,因为前两者数据库可以根据用户提交的SQL做预编译,只要是SQL语句是一样的,数据库就认为是同一次查询,数据库就可以根据查询结果做缓存或者优化。那什么样的SQL语句数据库认为是一样的呢?如下面:
Select * from userinfo where username = ‘junshan’ and id = 1
Select * from userinfo where username = ‘bobo’ and id = 2
显然这两条SQL语句是不一样的,如果你通过下面这样执行
statement.execute(“Select * from userinfo where username = ‘junshan’ and id = 1”)
或者
statement.execute(Select * from userinfo where username = ‘bobo’ and id = 2)
数据库完全认为这是两个毫不相干的SQL操作,不仅要重新解释这个SQL,构造SQL语法树,语法树的优化,准备执行环境等等。所有这些操作都用做一遍。但是很明显这两个SQL除了参数不一样,其他都是一样的,而对数据库来说,唯一不同的是,只要在第一次查询出来的结果集中根据参数值重新过滤一下即可,而前面的SQL解释,构建语法树,甚至数据都可能不要在数据库中重新捞一把。为此JDBC提供一种根据理想的PreparedStatement、和其子类CallableStatement。他们就是将单纯的SQL语句和SQL中的参数值分开,然后将值再映射过去。关于映射这一部分可以参数《深入分析Ibatis框架之系统架构与映射原理》。这样数据库就可以根据单纯的SQL做更多优化。上面的SQL应该这样写更为合理
Connection conn=DriverManager.getConnection(url,user,password);
java.sql.PreparedStatementst = conn.prepareStatement(Select * from userinfo where username = ? and
id = ?);
st.setString(0,’junshan’);
st.setInt(1,1);
st.execute();
前面说到都是在数据库服务端,但是在Oracle10g以后的JDBC中,在客户端以做了数据的缓存,这里的缓存只是针对和一个PreparedStatement对应的数据的缓存。这样做就可以让相同的SQL的执行完全不需要请求道数据库,达到更好的性能,但是这样必然会给客户端增加内存负担,在Oracle的官方说明中也提到了可能会导致严重的内存问题。
二、 Oracle JDBC驱动如何缓存
下面看一下Oracle JDBC客户端如何缓存:
客户端可以指定缓存一定数量的Statement,每个Statement持有两个buffers,一个是byte[]一个是char[]。这些buffers又在一个叫做Implicit Statement Cache的cache中。char[]主要是存储char类型的数据,而byte[]存储所有其他类型的数据。
当一个Statement被执行时这来两个buffer就将被创建,由于buffer创建是在获取数据之前,所以是不知道应该创建多大的buffer来存查询返回结果,为此只能按照Statement中申明的字段类型来分配buffer大小。分配的规则就是声明的字段类占用的字节数乘以最大的存储数量如VARCHAR2(10)就是10*2 bytes其他的类型如NUMBER、DATE都是安装22bytes分配还有一些如CLOB、BLOB存储的是数据地址,最大地址空间能达到4k所以至少分配4K给他们。
例如下面的SQL分配的buffer大小是:
CREATE TABLE TAB (ID NUMBER(10), NAME VARCHAR2(40), DOB DATE)
ResultSet r = stmt.executeQuery(“SELECT * FROM TAB”);
22 + (40 * 2) +22 = 124 bytes,这只是一行数据的buffer大小,Oracle JDBC默认是取十行,那分配的大小就是1240 bytes了。
按照这种分配方式是很容易出现内存问题的,加入有多个列都是都是VARCHAR2(4000)声明的字段,如果缓存100行,那么内存就很可能被用光了。
Oracle的建议是:
小心的定义每列的数据类型和最大的数据大小如不要每个VARCHAR2都需要定义为VARCHAR2(4000);还有就是设置fetchSize这个参数,就是分配多少行的缓存量,如有的SQL最多都是查询一行的数据你设置10行,那就是完全的浪费。
通常单个Statement引起的内存问题可能性有但是很小,最大的可能就是客户端会同时创建多个Statement并执行,还有一个潜在的问题就是缓存住Statement而不关闭,通常当Statement被关闭时这个 Statement持有的buffer也就被释放。但是如果被缓存的Statement都是比较大的数据很可能会撑爆内存。如果发现每条Statement分配的buffer较多,但是缓存的Statement数量有很多的话,就应该将缓存Statement的数量调小一点。
通常这个配置是下面的选项:
<datasources>
<local-tx-datasource>
<jndi-name>DB1DataSource_cm2</jndi-name>
<connection-url>jdbc:oracle:oci:@tbdb1_cm2</connection-url>
<connection-property name=”SetBigStringTryClob”>true</connection-property>
<connection-property name=”defaultRowPrefetch”>50</connection-property>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<min-pool-size>2</min-pool-size>
<max-pool-size>3</max-pool-size>
<idle-timeout-minutes>10</idle-timeout-minutes>
<prepared-statement-cache-size>75</prepared-statement-cache-size>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
<metadata><type-mapping>Oracle9i</type-mapping></metadata>
<user-name>taobao</user-name>
<password>taobao</password>
<security-domain>EncryptDB1Password_cm2</security-domain>
</local-tx-datasource>
上面提到是在向数据库查询时Oracle驱动缓存的数据量。但是在写入时Oracle驱动同样会分配空间给写入的参数。但是这个数据和查询的数据相比会小很多。同时数据的实际大小也是知道的,不需要想查询时都是分配最大的数量。但是如果是批量插入时Oracle为了提高执行性能不是按照每个Statement执行然后再重新配置另一个Statement的buffer而是同时缓存每个Statement的参数数据,然后一次执行所有的Statement,这样也可能会有大数据缓存的情况。但是这种情况在淘宝通常比较少爷容易控制。
三、 不同版本的区别
Oracle10g的以后版本对上面的方式增加了更多的控制,更加灵活一点。
10.2.0.4这个版本增加了oracle.jdbc.freeMemoryOnEnterImplicitCache这个选项,这选项可以控制当Statement被缓存时,可以控制这个Statement的锁持有的buffer要不要也一起缓存。例如前面缓存75个Statement但是可以设置不缓存这75个Statement的buffer,也就是每当重新使用被缓存的Statement时,驱动会重新再分配buffer给他们。设为TRUE时在Statement被缓存之前会释放他持有的buffer,为FALSE将会同时缓存Statement的buffer,默认是FALSE。
11.1.0.6.0对Statement的buffer控制更加精准。与前面相比,这个版本将每个Statement的buffer转移出来,组合成一个buffer cache,上面意思呢?就是当某个Statement被缓存时,他持有的buffer将不再是有freeMemoryOnEnterImplicitCache控制,而是将其buffer放到buffer cache中,当这个Statement被重新使用时再从buffer cache中重新恢复出来,这样做的好处就是不需要每次Statement从缓存中回复时都用给他重新分配buffer了。这样做也有另一个问题:就是每个Statement持有的buffer都不一样,怎么能把这些buffer放到buffer cache 中。打个比喻就是首先建一个大水池,水池中有多个形状的水箱,这些水箱的形状是可以变化,然后根据使用情况重新组成一个水箱,使用时把这个水箱装的水打走,不使用时再将这个水箱和水一起放到这个大水池中。这样就能充分利用这个大水池的水了。
11.1.0.7.0这个版本在前面版本的基础上给buffer cache又增加了一个控制项oracle.jdbc.maxCachedBufferSize,他就是控制在buffercache 中最大的buffer的大小。Oracle驱动把个别非常大的buffer不保存在buffer cache中,这些比较大的buffer还是根据前面的方式当持有的Statement被缓存时释放buffer,当重新使用时再重新分配。这种方式主要是优化了大水池的水的重复利用情况,防止水被少数几个大买家独占,而大部分小买家却老是没水喝。
这个版本中还有一个控制项是oracle.jdbc.useThreadLocalBufferCache,通常前面所说的buffer cache都是和一个connection像关联的,但是通常一个应用会建立多个connection,在pool中。但是通常一个客户端查询数据同一时刻都是通过一个线程来完成的,这样又可以将buffer cache关联到用户的线程而不是connection。
11.2中又增加了一个控制项是oracle.jdbc.implicitStatementCacheSize,他可以控制statement cache的大小。默认是0。
以上说的这些控制项都可以通过OracleConnection.setXXX来设置。
分享到:
相关推荐
- **自动内存管理**:Oracle 12c改进了内存管理机制,如Automatic Memory Management,自动调整SGA和PGA的大小,简化数据库管理员的工作。 - **高级压缩**:提供了更高效的表和索引压缩选项,节省存储空间。 - **...
- **Memory Optimization**:内存优化,提高数据库的性能,特别是OLTP(在线事务处理)系统。 - **SQL Performance Analyzer**:SQL性能分析器,帮助识别和优化SQL查询性能问题。 - **Fine-grained Auditing (FGA...
在性能优化方面,Oracle 9i引入了自动内存管理(Automatic Memory Management),简化了数据库管理员的工作,自动调整SGA(System Global Area)和PGA(Program Global Area)的大小,以达到最佳性能。此外,SQL优化...
- **Automatic Memory Management (AMM)**:自动内存管理功能进一步优化了数据库性能,自动调整SGA和PGA的大小。 - **SQL Plan Management (SPM)**:通过维护和重用执行计划,SPM提高了SQL查询的性能和稳定性。 2...
- **Automatic Memory Management**:Oracle 11g R2引入了自动内存管理功能,简化了内存分配,DBA无需手动调整SGA和PGA参数。 - **Real Application Clusters (RAC)**:11g R2对RAC进行了优化,提高了多节点数据库...
1. 数据库自动存储管理(Automatic Storage Management, ASM):Oracle 10g引入了ASM,提供了一种集成的存储解决方案,简化了存储管理,提高了性能和可用性。 2. Real Application Clusters(RAC):Oracle 10g的...
11. Oracle 进程:在 Oracle 10G 中,MMAN 进程负责实现 Automatic Shared Memory Management。 12. PGA 组成部分:PGA (Program Global Area) 包括会话变量、分析信息和排序空间,但不包括绑定信息,绑定信息属于 ...
3. **自动化管理**:Oracle Database 19c引入了更高级别的自动化工具,如Automatic Indexing和Automatic Memory Management,这些功能可以自动调整数据库设置以优化性能,减轻DBA的工作负担。 4. **安全性增强**:...
这包括了查询优化、内存管理、I/O优化、并行处理和资源调度等多个方面。查询优化是通过优化SQL语句,避免全表扫描,利用索引,合理使用连接方式等手段,提升数据检索速度。内存管理则涉及到SGA(System Global Area...
它引入了许多新特性和性能改进,例如Advanced Compression、Automatic Memory Management、Real Application Clusters (RAC)增强以及对XML DB的改进等。使用Instant Client 11.2,你可以连接到运行相同或更低版本的...
ASM(Automatic Storage Management)是Oracle提供的存储管理解决方案。遇到问题时,可以采取以下步骤: 1. **检查ASM配置**:确保ASM配置正确无误。 2. **监控ASM状态**:使用v$asm_diskgroup视图监控ASM磁盘组的...
Oracle Database 11g是Oracle的一个重要版本,引入了诸如Automatic Memory Management、RAC(Real Application Clusters)改进、Data Guard增强等功能。 3. **解压与安装**: 解压"Instantclient_11_2.rar"后,...
- **内存管理**:自动内存管理功能,简化了内存配置。 - **安全性**:支持最新的加密标准,确保数据安全传输。 - **Unicode支持**:全面支持Unicode,实现跨语言的数据交换。 在使用这些版本的Instant Client时,...
Oracle 12c引入了许多新特性,如Multitenant架构、Automatic Memory Management优化、SQL Plan Management改进等,这些在Instant Client中都能得到体现。 在描述中提到“oracle网站总崩”,这可能是指下载Oracle...
- **Automatic Memory Management (AMM)**:自动内存管理简化了数据库管理员的工作,通过自动调整SGA和PGA内存,优化了数据库性能。 - **Advanced Compression**:引入了高级压缩技术,可对数据、索引、备份等进行...
在11.2版中,Oracle引入了许多新特性、性能提升和稳定性增强,比如Advanced Compression(高级压缩)、Automatic Memory Management(自动内存管理)以及Enhanced Parallel Query(增强并行查询)等。对于开发人员和...
- **连接管理**:通过JDBC、ODBC等方式连接Oracle数据库。 - **数据访问**:使用SQL语句进行数据操作,或者通过PL/SQL编写存储过程和函数。 - **索引设计**:合理创建和管理索引以提升查询效率。 - **并发控制**...
#### 九、大内存:离堆存储(Big Memory: Off-Heap Store) 针对大数据量的缓存需求,Ehcache提供了离堆存储选项,可以在不占用Java堆内存的情况下存储大量数据。这部分内容详细介绍了离堆存储的工作原理、优势以及...
- **SPM**:共享内存管理器(Shared Memory Manager),负责管理DB2实例内的共享内存区域。它是DB2多线程架构的关键组件之一。 - **FCM**:文件控制管理器(File Control Manager),用于管理数据库文件系统,包括...
6. channels.type:通道的类型,例如 memory-channel、JDBC-channel、file-channel 等。 7. sinks.type:接收器类型,例如 avro、logger、HDFS、Hbase 和 file-roll 等。 四、Flume 启动 1. 启动 Flume:使用命令 ...