关于online redo log 和datafile 的一些误区:
1. DBWR 数据库写入进程
DBWR 进程负责将脏数据块从数据缓存(database block buffer)写回磁盘.
2. LGWR 日志写入进程
LGWR (the log writer process)负责将日志缓冲区中的数据写入重做日志。
3. PMON 进程监视进程
4. SMON 系统监视进程
5. CKPT 检查点进程
6. ARCHn 归档进程
想查看更多进程信息请查询相关文档。本例主要帮助理解DBWR 和LGWR。
当一个transaction commit 的时候,oracle 做了什么工作:
1. lgwr 把redo buffer 写入到redo logfile
2. dbwr 把data buffer 写入到datafile
3. 在commit 前lgwr 和dbwr 做了什么工作,啥都不干???
4. commit 前服务器突然停机,数据会丢失吗,恢复机制是什么
5. commit 后服务器突然停机,开机oracle 做了什么
实验前先看看实验环境:
OS:RHEL5.5
ORACLE:10.2.0
USER:TT
图中可以看出tt 的缺省表空间是tt,数据文件是/u01/oracle/oradata/elison/tt.dbf
缺省临时表空间是temp。
开始实验:
实验一:
1.首先创建一个table text,然后往里面插入10 条记录。此时没有commit.
查询,过程执行成功,添加了10 条记录
2. 此时用strings 查询redolog 和datafile 发现没有‘elison2011.7.18’这字符串
说明redo buffer 和data buffer 还没有写入磁盘文件。
(忘记说明文件的存放位置了,以下补充)
我的redo log 文件是:
/u01/oracle/oradata/elison/redo01_1.log
/u01/oracle/oradata/elison/redo01_2.log
/u01/oracle/oradata/elison/redo02_1.log
/u01/oracle/oradata/elison/redo02_2.log
/u01/oracle/oradata/elison/redo03_1.log
/u01/oracle/oradata/elison/redo03_2.log
每组有两个成员,所以每组查询一个成员文件即可,原理大家懂的,以下我只查
redo01_1.log redo02_1.log redo03_1.log 和datafile 中的tt.dbf 这四个文件即可。
Datafile:
/u01/oracle/oradata/elison/tt.dbf
在第一步中我们添加了10 条含有’elison2011.7.18’字符串的记录。所以我们只需要
查看上面说的四个文件即可知道buffer 有没有往磁盘里写东西,如果有,写了哪些磁盘?
从上图可以看出这四个文件里都没有’elison2011.7.18’这字符串,所以得出结论:
Transaction 没有commit,buffer 是不会往磁盘文件里写的。(结论1)
(似乎到目前为止,这句话是正解的!没错吧)
3.接着进入第三步,我们commit transaction.接着查询这四个文件。
注意啦!此时redo log 中有一组文件里有’elison2011.7.18’字符串,这说明了什么,
大家懂的!但是数据文件里没有’elison2011.7.18’字符串,得到结论:
Transaction commit 后,redo buffer 写入了磁盘文件,但data buffer 没有写入磁盘
文件。(结论2)
这似乎也是正解的,大家没有意见吧!有意见的请保留!
4.接着我们用sysdba 执行alter system checkpoint.
此时发现data buffer 写入数据文件了(当然写入了,要不然就是oracle 有问题了,
手工触发checkpoint 也有失误,那还了得)。

实验二:
我们把实验一的第一步改一改:此时我们创建一个过程,不再往表了插入10 条记录,
我们要插入1000 条或更多!
1. 创建过程(插入1000 条记录)
begin
for i in 1 .. 1000
loop
insert into text values(i,'elison_insert_1000');
end loop;
end;
/
和实验一相同,此时transaction 没有commit;
此时,再strings 那四个文件的话,发现redo log 里有了'elison_insert_1000'记录,
但data file 没有'elison_insert_1000'记录,说明了什么,大家先想想。
直接上图(悲剧,因为前面忘记截图,到第三步的时候用strings 得到的记录太多了,
直接把securecrt 的缓存给刷了,所以不能截图了,大家有兴趣自己实验一下)
2. 创建过程(插入1000 条记录)
begin
for i in 1 .. 50000
loop
insert into text values(i,'elison_insert_50000');
end loop;
end;
/
和实验一相同,此时transaction 没有commit;
此时,再strings 那四个文件的话,发现redo log 里有了'elison_insert_27000'记录,
data file 不但有了'elison_insert_50000' 记录, 也有了前面第一步中
‘elison_insert_1000’的记录(第一步的事务还没有提交呢),这说明了什么,大家先想
想。
(注意:这里为什么是50000 或者更多,这个与oracle 的设置参数,内存分配等等有关……)

结论:1.从第一个步骤我们可以看出,事务虽然没有提交,但oracle 的lgwr 机制会触
发lgwr 进程把redo buffer 写入磁盘,但dbwr 并没有被触发。(结论3)
LGWR 触发条件:
1,每三秒钟超时(timeout)
2.阀值的达到:
Redo log buffer 1/3 满
Redo log buffer 拥有 1MB 的脏数据
3.用户提交
4.在DBWn 写之前
DBWR 触发条件:
1) 当进程在辅助LRU 链表和主LRU 链表上扫描以查找可以覆盖的buffer header[空闲缓冲区]时,如
果已经扫描的buffer header 的数量到达一定的限度(由隐藏参数:_db_block_max_scan_pct 决定)时,
触发DBWR 进程。_db_block_max_scan_pct 表示已经扫描的buffer header 的个数占整个LRU 链表上buffer
header 总数的百分比。这时,搜索可用buffer header 的进程挂起,在v$session_wait 中表现为等待“free
buffer wait”事件,同时增加v$sysstat 中的“dirty buffers inspected”的值。(can query by x$kvit)
2) 当DBWR 在主LRUW 链表上查找已经更新完而正在等待被写入数据文件的buffer header 时,如果找
到的buffer header 的数量超过一定限度(由隐藏参数:_db_writer_scan_depth_pct 决定)时,DBWR 就
不再继续往下扫描了, 而转到辅助LRUW 链表上将其上的脏数据块写入数据文件。
_db_writer_scan_depth_pct 表示已经扫描的脏数据块的个数占整个主LRUW 链表上buffer header 总数的
百分比。
3) 如果主LRUW 链表和辅助LRUW 链表上的脏数据块的总数超过一定限度,也将触发DBWR 进程。该限
度由隐藏参数:_db_large_dirty_queue 决定。
4) 发生增量检查点(incremental checkpoint)或完全检查点(complete checkpoint)时触发DBWR。
5) 每隔三秒钟启动一次DBWR。
6) 将表空间设置为离线(offline)状态时触发DBWR。
7) 发出命令:alter tablespace … begin backup,从而将表空间设置为热备份状态时触发DBWR。
8) 将表空间设置为只读状态时,触发DBWR。
9) 删除对象时(比如删除某个表)会触发DBWR
以上触发条件是网上摘录的
2.从第二个步骤我们可以看出,事务虽然没有提交,但oracle 的lgwr 机制会触发lgwr
进程把redo buffer 写入磁盘,dbwr 也触发了。(结论4)
结论3 和结论4 证明了结论1 和结论2 是错误的。
总之,一句话,事务提交,redo log buffer 一定写入磁盘,data buffer 有可能写入
有可能不写入(这要看dbwr 是否触发,看触发条件是否满足)。
事务没有提交,redo log buffer 有可能写入磁盘(原因很多,看上面LGWR 的触发条
件),data buffer 有可能写入有可能不写入(这要看dbwr 是否触发,看触发条件是否满足),
data buffer 如果有写入,那写入部分的redo log 信息一定写入了磁盘(redo log buffer
要比data buffer 先写入磁盘,这个机制很重要,关系到数据是否丢失的问题),如果这时
候,服务器down 机了,下次重启后可以根据redo log rollback dirty data。