2.1 控制文件
控制文件包含了数据库中所有其他文件的状态信息。
控制文件包含了如下几类数据:
A. 数据库信息记录(一条)
B. 数据文件记录(每个数据文件一条)
C. 线程记录(每个线程一条。注:每个实例一个线程)
D. 日志文件记录(每个日志文件一条)
E. 文件名记录(每个数据文件或者日志文件成员一条)
F. 日志历史记录(每个已经完成的日志文件一条)
控制文件的被后面文档引用到的字段如下,后面是引用该字段的章节:
2.1.1 数据库信息记录(控制文件)
所含字段:
A. resetlogs timestamp: 8.2
B. resetlogs scn: 8.2
C. enabled thread bitvec: 8.3
D. force archiving scn: 3.8
E. database checkpoint thread(thread record index) : 2.13, 3.10
2.1.3 数据文件记录(控制文件)
A. thread checkpoint structure: 2.12, 3.4, 8.3
B. thread-open flag: 3.9, 3.11, 8.3
C. current log (logfile record index)
D. head and tail (logfile record indices) of list of logfiles in thread: 2.8
2.1.4 日志文件记录(控制文件)
A. log sequence number: 2.7
B. thread number: 8.4
C. next and previous (logfile record indices) of list of logfiles in thread: 2.8
D. count of files in group: 2.8
E. low SCN: 2.7
F. next SCN: 2.7
G. head and tail (filename record indices) of list of filenames in group: 2.8
H. "being cleared" flag: 10.3
I. "archiving not needed" flag: 10.3
2.1.5 文件名记录(控制文件)
A. filename
B. filetype
C. next and previous (filename record indices) of list of filenames in group: 2.8
2.1.6 日志文件历史记录(控制文件)
A. thread number: 2.11
B. log sequence number: 2.11
C. low SCN: 2.11
D. low SCN timestamp: 2.11
E. next SCN: 2.11
2.2 数据文件头
数据文件头部分的被后面文档引用的字段如下,后面跟的是引用该字段的章节:
A. datafile checkpoint structure: 2.14
B. backup checkpoint structure: 4.1
C. checkpoint counter: 2.16, 3.4, 5.3, 6.2
D. esetlogs timestamp: 8.2
E. resetlogs SCN: 8.2
F. creation SCN: 8.1
G. online-fuzzy bit: 3.5, 6.7.1, 8.1
H. hotbackup-fuzzy bit: 4.1, 4.4, 6.7.1, 8.1
I. media-recovery-fuzzy bit: 6.7.1, 8.1
2.3 日志文件头
日志文件头部分的被后面文档引用的字段如下,后面跟的是引用该字段的章节:
A. thread number: 2.7
B. sequence number: 2.7
C. low SCN: 2.7
D. next SCN: 2.7
E. end-of-thread flag: 6.10
F. resetlogs timestamp: 8.2
G. resetlogs SCN: 8.2
Redis对linux socket的封装,虽然在该封装中也含有对unix socket的封装,但是普遍来说使用的tcp socket。和上一篇的epoll的封装类似,都是通过调用底层的socket的函数完成一些列的方便的函数调用封装。
源码anet.h anet.c
分析主要包含以下几个封装函数(这里仅介绍关于Tcp socket的封装函数)
anetTcpconnect:创建socket并调用底层的connect进行连接。
anetTcpNonBlockConnect:和anetTcpConnect功能类似,但是设置连接的socket为非阻塞的。
anetRead:调用底层的read对socket中的内容进行读取。
anetWrite:调用底层的write向socket写入内容。
anetTcpServer:创建监听socket,并调用bind和listen启动服务器开始监听端口。
anetTcpAccept:调用accept,接收客户端的连接。
当然还有其他的辅助的函数,像是anetResolve解析地址,以及设置socket属性的一些函数如anetNonBlock anetTcpNoDelay anetTcpKeepAlive anetPeerToString等。
说明这里的对socket的封装的主要目的是为了方便Redis的网络调用这里的函数主要被下一篇将要介绍的Redis网络通信实现所调用。
不拾掇Java有好几年了(N>3吧),之所以写这篇文章其实是纯粹是为了给开发人员一些好的使用jdbc真正去减少交互和提升批量处理batch update性能的例子; 如果你是DBA,那么工作之余你可以把这篇文章推荐给开发看一下, 也许这些例子他已经知道了, 倘若他不知道,那么也算一种福利了。
能考虑到在应用程序client和 数据库服务器DB server间减少交互时间,批量更新处理的绝对是有助于重构和优化代码的好同志; 但这种优化一定要注意方法,如果是自行去重新发明一种轮子的话, 效果往往是不如人意的。
例如Tom Kytes曾在他的著作里提到这样2个例子,他去协助开发的2家企业的在研发应用的过程中,分别通过应用程序自己去在Oracle中实现了user profile和advanced queue的功能, 有一定经验的朋友肯定会知道这2样功能其实Oracle Enterprise Edition企业版软件都是原生态支持的,而自己在DB中去实现它们,最终结果自然是项目的失败。
类似的有朋友在开发过程中,为了优化Oracle JDBC中的批量更新update操作,想到了这样的方式,例如要插入INSERT 15000行数据,则在JAVA层面 将15000条INSERT语句拼接在一个PL/SQL block里,这15000条SQL涉及到的变量仍使用PreparedStatement.setXXX方法带入,其在JAVA层面的SQL STRING,如:
begin --我是一个拼接起来的SQL匿名块 insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); insert into insertit values(?,?,?,?); ..................... commit ; end;
如上15000个INSERT拼接成一个PL/SQL block,一次性PreparedStatement.execute()提交给DB,通过这样来减少Jdbc Thin Client与DB Server之间的交互。先不说别的,光在JAVA里循环控制拼接SQL的写法多少是要花点时间的。
这种写法和 JDBC里PreparedStatement.setExecuteBatch、或者PreparedStatement+addBatch()+executeBatch()的执行效率究竟如何呢?
我们在一个简单的JAVA程序里测试这三者写法的实际性能,并窥探其在DB中的表现,以下为JAVA代码(多年不写,就勿纠结代码风格):
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package apptest; import oracle.jdbc.*; import java.sql.*; /** * * @author xiangbli */ public class Apptest { /** * @param args the command line arguments */ public static void main(String[] args) throws SQLException { // TODO code application logic here try { Class.forName("oracle.jdbc.driver.OracleDriver"); }catch(Exception e){} Connection cnn1=DriverManager.getConnection("jdbc:oracle:thin:@192.168.56.101:1521:cdb1", "c##maclean", "oracle"); Statement stat1=cnn1.createStatement(); cnn1.setAutoCommit(false); ResultSet rst1=stat1.executeQuery("select * from v$version"); while(rst1.next()) { System.out.println(rst1.getString(1)); } long startTime = System.currentTimeMillis(); long stopTime = System.currentTimeMillis(); String str="begin \n --我是一个拼接起来的SQL匿名块 \n"; int i; for(i=0;i<=15000; i++) { str= str.concat(" insert into insertit values(?,?,?,?); \n"); } str=str.concat(" commit ; end; "); System.out.print(str); cnn1.createStatement().execute("alter system flush shared_pool"); System.out.print("\n alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第一次测试 \n"); PreparedStatement pstmt = cnn1.prepareStatement(str); int j; for (j=0;j<=15000;j++) { pstmt.setInt(1+j*4, 1); pstmt.setInt(2+j*4, 1); pstmt.setInt(3+j*4, 1); pstmt.setInt(4+j*4, 1); } // System.out.println (" Statement Execute Batch Value " +((OraclePreparedStatement)pstmt).getExecuteBatch()); startTime = System.currentTimeMillis(); pstmt.execute(); stopTime = System.currentTimeMillis(); System.out.println("拼接15000条INSERT SQL 第一次运行的耗时 Elapsed time was " + (stopTime - startTime) + " miliseconds."); startTime = System.currentTimeMillis(); pstmt.execute(); stopTime = System.currentTimeMillis(); System.out.println("拼接15000条INSERT SQL 第二次运行的耗时 Elapsed time was " + (stopTime - startTime) + " miliseconds."); cnn1.createStatement().execute("alter system flush shared_pool"); System.out.print("\n alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试 \n"); startTime = System.currentTimeMillis(); int batch=1000; PreparedStatement pstmt2 = cnn1.prepareStatement("insert into insertit values(?,?,?,?)"); ((OraclePreparedStatement)pstmt2).setExecuteBatch(batch); for (int z=0;z<=15000;z++) { pstmt2.setInt(1, z); pstmt2.setInt(2, z); pstmt2.setInt(3, z); pstmt2.setInt(4, z); pstmt2.executeUpdate(); } ((OraclePreparedStatement)pstmt2).sendBatch(); cnn1.commit(); stopTime = System.currentTimeMillis(); System.out.println("batch size= "+batch+