分类: Oracle
2008-04-28 09:39:54
三:关于low cache rba与on disk rba的理解:
简单说:low cache rba就是CKPT记录的DBWR写的进度。
on disk rba就是LGWR的写进度。
如果数据库carsh,low cache rba是恢复的起点,on disk rba是恢复的终点。
阐述一下:dbwr成功写完后并不把此刻scn信息写到控制文件中,只有CKPT才更新控制文件和数据文件头,dbwr只要成功将dirty data写入数据文件就是成功, CKPT只要能将最新DBWR写完的SCN更新到控制文件和数据文件头就算成功。但是由于CKPT进程不是实时更新dbwr写完的scn到控制文件中,而是采用每3妙更新一次的策略,因此最后有ckpt进程写进控制文件的scn信息有可能不是当前dbwr刚刚写完的scn值。这点应该注意,也就是说dbwr写的进度与ckpt进程更新控制文件的进度是不同的。
关于检查点的一点具体应用讨论:
Commit成功后,数据还会丢失吗?
对于Oracle来说,用户所做的DML操作一旦被提交,则先是在database buffer cache 中进行修改,同时在修改之前会将数据的前镜像保存在回滚段中,然后将修改之前和修改之后的数据都写入到redo log buffer中,当接收到commit命令之后,则redo log buffer开始写redo log file ,并且记录此时的scn,当redo log file 写完了之后,表示这次事务提交操作已经确认被数据库记录了,只有当redo log file 写成功了,才会给用户 Commit completed 的成功字样。而对于Database buffer cache中的dirty buffer则会等待触发DBWn才写入,但是如果此时断电,则数据已经被记录到了redo log file中,系统在重新启动的时候,会自动进行嵌滚和回滚来保证数据的一致。所以,只要是commit成功的了,数据不会丢失!
数据库发生一次DBWn,是否将所有buffer cache 中的dirty buffer 都写入,还是先将脏队列中的数据写入?
这话看起来有道理,但实际上,dbwr在写的时候又不断地在产生dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。
所有的buffer,不在LRU list上就在dirty list上, dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
所以说要是 dbwr将 dirty list也好, lru list上的也好,要实现全部写入,都是一个现实系统中很难存在的现象。dirty 总是在不断的产生,dbwr总是在不断地写,增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性。
data block里面不是也有SCN吗?和文件头里面的SCN有什么关系?什么时候被更新?代表的是是什么含义?
data block 里面的SCN是当 block 被更改的时候的 SCN
而数据文件有那么多 block,自然不同的 block有不同的 SCN
block中存在 block SCN 和 ITL 中的commit SCN
block SCN 又在块头和块位都有,若不一致意味着block损坏(热碑可能出现这个情况,需要从redo log中拷贝回来,若是正在修改的过程中由于进程死掉则 pmon负责清理。若 由于一些以外发生这样的不一致的情况,则查询的时候出现 1578 错误,当然该错误号也可能是 物理磁盘损坏,这里表示逻辑的损坏!)
这个头和尾的 SCN 的检查时机跟这两个参数有关:
db_block_checking boolean FALSE
db_block_checksum boolean FALSE
该2参数信息请查阅
而ITL 中的 commit SCN 则跟 consistent gets and delay block cleanout 有关
数据文件头的 SCN 是检查点发生时更新的,代表着 当 恢复的时候从这个 SCN 点 开始在 log file 中寻找 redo 开始做恢复。
看下面的操作!
___________________________________________________________
sys@DBAP01> select max(ktuxescnw*power(2,32)+ktuxescnb) from x$ktuxe;
MAX(KTUXESCNW*POWER(2,32)+KTUX
------------------------------
52211024
已用时间: 00: 00: 00.00
sys@DBAP01> alter system checkpoint;
系统已更改。
已用时间: 00: 00: 00.06
sys@DBAP01> select CHECKPOINT_CHANGE# from v$database;
CHECKPOINT_CHANGE#
------------------
52211055
已用时间: 00: 00: 00.00
sys@DBAP01> select max(ktuxescnw*power(2,32)+ktuxescnb) from x$ktuxe;
MAX(KTUXESCNW*POWER(2,32)+KTUX
------------------------------
52211053
已用时间: 00: 00: 00.00
sys@DBAP01>
怎么解释这个现象?
解答: x$ktuxe 计算出来的是已经结束的最新的事务的commit scn ,所以可小于当前系统scn。 检查点 scn 自然也小于当前系统scn。 但是 检查点scn 和 x$ktuxe 计算出来的大小却倚赖于 系统状况了。
current scn 是 系统当前所产生的最大 scn ,可能是当前未结束事务所产生的scn。 在9i 的 dbms_flashback.get_system_number 可以得到这个值,这个值应该是大于等于 x$ktuxe SCN (这个view 记录的是 当前数据库结束事务的最大scn)
关于SCN的一些理解:
在控制文件,数据文件头,数据块,日志文件头,日志文件change vector中都有SCN,但其作用各不相同。
数据文件头中包含了该数据文件的checkpoint SCN,表示给数据文件最近一次执行检查点操作时的SCN.
日志文件头中包含了low scn,next scn,表示给日志文件包含有从low scn到next scn的redo record.
控制文件中包含了每个数据文件的checkpoint SCN,stop SCN,每个日志文件的low scn,next scn。控制文件中checkpoint scn同数据文件头中checkpoint scn相同,除非数据文件被手工替换掉.控制文件中的low scn,next scn同日志文件中low scn和next scn相同。
在数据库正常运行时,控制文件中对应数据文件的stop SCN都是最大值.
在正常关闭数据库的情况下,在关闭前会执行一次检查点工作当oracle会将数据缓冲区上的内容全部写回到磁盘中,然后更新控制文件中对应数据文件的stop SCN,使其等于checkpoint SCN。
但在异常当机的情况下,由于最后一次检查点未进行或进行中间被中止,因而在控制文件,就存在部分的数据文件stop SCN为最大值。
在数据库重新启动后,会检查控制文件中对应每个数据文件的stop SCN,如果stop SCN不等于控制文件中对应每个数据文件的checkpoint SCN,就会使用日志文件redo从checkpoint SCN开头到stop SCN为止的全部数据库操作.
在定位到底使用哪个日志文件的时候,并不是用数据文件中的 low scn 去框,也不是 只要在日志文件的low scn and next scn 之间就利用该日志文件。而是在数据文件头中有 RBA 的记录,RBA 包含了日志序号、block number 、slot number 。 这样可以直接定位到日志文件(归档日志文件)和具体的位置。
在确定了哪个数据文件须redo后,oracle会比较change vector(向量)中的SCN和数据文件数据块中的SCN,如果change vector的SCN小于数据块的scn,则跳过此change vector,否则redo数据块中ITL中还有SCN,但它的作用是用于产生一致性读快照。
commit的时候加一,其他很多时候也会加1,只要数据库发生了变化都会增加。
很多时候,能否举一些例子
dml一发生即使没有提交也会增加scn, job进程一样产生scn,只要对数据库中文件发生任何的改变都有可能产生scn,SCN: system change number, not system commit number .也就是 系统发生变化 所产生的一个时间点标志。不是提交的标志,只是因为提交也是系统的变化之一而已。
这句话我应该更准确第表达一下:
如果一个dml导致产生事务,则会产生一个scn。这个意思是说
如果一个事务包含多个dml,则只有第一个初始产生事务的dml产生scn,提交的时候又是一个scn。
如果一个事务只有一个dml,那么看起来就是dml产生一个scn,提交或者回滚产生一个scn。
所以可以把结论定义为 事务的开始 和事务的结束都会导致 SCN 的增加,同一个block上在一个事务中连续发生255个DML后scn也会增加。
检查点的发生和日志的关系:
解答:
检查点的发生,跟写日志文件是没有必然联系的。
检查点发生,通知 DBWR 写数据文件,写完后ckpt更新控制文件和数据文件头。
当DBWR 写 数据块的时候若发现 数据块的 相关 RDBA (位于日志文件的位置) 的 log block 还没有被写入日志文件,则在dbwr写块之前必须通知lgwr把log buffer 中日志写入日志文件。
关于检查点等待事件:
有些事件的产生必须等待检查点的完成,才能开始数据库的其它操作:
日志文件切换就是其中一个事件,日志切换必须等待检查点完成。
log file switch (checkpoint incomplete) 这个等待事件本身也说明,日志切换时产生的检查点是需要等待的,这个日志文件所对应脏块全部写完后,检查点进程更新控制文件和数据头,然后这个检查点才能算完成。
也就是说日志切换必须等待检查点完成,而检查点在等待DBWn完成。
这种等待DBWn完成的检查点,最后一步写入控制文件和数据文件头的SCN,肯定是DBWn完成的最后一块的SCN。
检查点为什么要等待dbwr完成后才进行切换(log switch)?
log switch时,是不能立即switch到active状态的日志文件的,此时切换进程必须等待。active表示该log group还没有完成归档(归档模式下)或者该log group有进行instance recovery需要用到的日志。所以当checkpoint发生时,如果dbwr还没有写完它该写完的dirty buffers(该checkpoint时间点以前产生的dirty buffers, 靠scn判断),则该log group处于active状态,不会进行日志切换,当然也不会发生日志文件被覆盖的问题了。
如果没有设置archive log ,在检查点发生后,发生log switch一个轮回,log file是否会被覆盖掉?
当检查点发生后,会触发lgwr,lgwr会把此时SCN以前在redo buffer中的所有操作写到redo log file,同时lgwr也会触发dbwr进程,dbwr也开始把此刻以前database buffer中的dirty buffer队列中的操作写入data file。
其实检查点发生后,就是lgwr和dbwr写buffer到磁盘文件的过程,但是两者的读写速度时不同的,dbwr写buffer到数据文件的过程相对较慢,因为dbwr写过程是一个随机读取存储的过程。Lgwr写buffer到redo文件的过程比dbwr要快很多,因为lgwr是顺序读取写入的。
由于以上lgwr和dbwr写操作的速度不同,就产生了一个等待问题。即当lgwr
轮循一圈后,要进行日志切换,覆盖redo log file,但是此时dbwr还没有写完,那么lgwr就会出现等待,oracle也会hang在那里,同时alter文件中会提示一个相应的提示checkpoint not complete。等检查点完成后数据库自动恢复正常。
当log switch时,会触发检查点,标记检查点时,DBWR要把log file中covered by the log being checkpointed的数据写入到数据文件上,如果Dbwr没有写完,那么前一个logfile是不能被覆盖的。因此必须等检查点完毕,也可以说是将 要被覆盖的日志相关的数据块全部写入数据文件后,该日志文件才能被覆盖!
如果这种情况出现,alert文件中会记录checkpoint not complete事件,这通常表明你的dbwr写入过慢或者logfile组数过少或log file太小。