有同学提问关于闪回数据库日志为什么远少于redo log? RVWR( Recovery Writer)每3s检查flashback generate buffer中的block before image的具体算法是如何的? 是否每一次block change都需要RVWR写出block before image 到flashback log?
为了实现闪回数据库,Oracle需要记录数据块的前景象before image到一种新的日志中,这种日志被命名为flashback database logs闪回日志。 闪回日志总是被循环复用,连续写出。
在一个实例中当一个数据块首次被修改时,前台进程会将该数据块的before image拷贝到位于shared pool中的flashback log buffer中,RVWR进程定期地将flashback log buffer中的记录刷新到磁盘上。 在DBWR进程可以写出相关脏块到磁盘之前,DBWR必须保证该buffer header相关FBA(Flashback Byte Address)的flashback log buffer已经写出到闪回日志。 这被称作 先写闪回日志 机制。
在常规的闪回日志维护操作中 , RVWR进程定期地插入闪回标记(flashback markers)到flashback database logs中。 闪回标记(flashback markers)的作用是在闪回数据库是告知Oracle如何flashback 到之前的某个时间点。 在闪回操作执行过程中, Oracle 会用闪回标记(flashback markers)中的信息来决定多大范围的flashback database log需要用来还原数据块景象block image; 之后Oracle 会利用前向恢复(forward recovery)的方式把数据库穿越到用户指定闪回的SCN或者时间点。
flashback markers for example:
**** Record at fba: (lno 1 thr 1 seq 1 bno 4 bof 8184) ****
RECORD HEADER:
Type: 3 (Skip) Size: 8132
RECORD DATA (Skip):
**** Record at fba: (lno 1 thr 1 seq 1 bno 4 bof 52) ****
RECORD HEADER:
Type: 7 (Begin Crash Recovery Record) Size: 36
RECORD DATA (Begin Crash Recovery Record):
Previous logical record fba: (lno 1 thr 1 seq 1 bno 3 bof 316)
Record scn: 0x0000.00000000 [0.0]
**** Record at fba: (lno 1 thr 1 seq 1 bno 3 bof 8184) ****
RECORD HEADER:
Type: 3 (Skip) Size: 7868
RECORD DATA (Skip):
**** Record at fba: (lno 1 thr 1 seq 1 bno 3 bof 316) ****
RECORD HEADER:
Type: 2 (Marker) Size: 300
RECORD DATA (Marker):
Previous logical record fba: (lno 0 thr 0 seq 0 bno 0 bof 0)
Record scn: 0x0000.00000000 [0.0]
Marker scn: 0x0000.0060e024 [0.6348836] 06/13/2012 15:56:35
Flag 0x0
Flashback threads: 1, Enabled redo threads 1
Recovery Start Checkpoint:
scn: 0x0000.0060e024 [0.6348836] 06/13/2012 15:56:12
thread:1 rba:(0x80.180.10)
Flashback thread Markers:
Thread:1 status:0 fba: (lno 1 thr 1 seq 1 bno 2 bof 8184)
Redo Thread Checkpoint Info:
Thread:1 rba:(0x80.180.10)
**** Record at fba: (lno 1 thr 1 seq 1 bno 2 bof 8184) ****
RECORD HEADER:
Type: 3 (Skip) Size: 8168
RECORD DATA (Skip):
End-Of-Thread reached
需要注意的是不是数据库中的每一次block change 都会触发before image被记录到闪回日志flashback log中。 如果每一次block change都记录flashback log record 那么闪回日志会要比 redo log大的多!因为毕竟flashback log 是记录整个块的before image 而 redo log只记录 change vector 。 Oracle对于闪回日志使用一种即能够保证可以讲数据库一致地穿越到某个历史时间点的状态,又不过分造成I/O损耗和生成大量闪回日志的方法:
对于hot block热块,Oracle仅在一段时间内记录一次block image到闪回日志; Oracle 内部通过闪回分界线(flashback barriers)实现这一点。在常规数据库状态下,flashback barriers被周期性的触发(一般为15分钟),对应每一个闪回分界线(flashback barriers)会有一个(flashback markers)被写出到闪回日志。
对于热块, 即那些频繁被change的数据库块, 闪回日志算法要求限制其写出到闪回日志的版本数。举例来说, 在15分钟内对于某个数据块仅限其写出一个版本到flashback log。虽然更多版本的before image有助于减少闪回数据库的时间,但是最小化有效闪回日志的容量是更重要的因素,比起实际闪回所用的时间来说。 为了实现这个目标,闪回日志算法引入了闪回分界线(flashback barriers), flashback barriers会被定期地触发,典型的例如15分钟一次。 对应每一个flashback barriers会有一个闪回标记(flashback markers)被插入到闪回日志中。常规情况下,对于每一个被修改的数据块在一个闪回区域(被分界线barriers分割的区域)内仅记录一个block image ,无论这个数据块在这段区域内被修改了多少次、被写出过多少次到磁盘上。
这就是为什么闪回日志flashback log要原少于redo log的产生量!
好了说了,这么多如果不亲身体验一下就太虚了, 我们来做以下的测试。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
SQL> select * from global_name;
GLOBAL_NAME
--------------------------------------------------------------------------------
www.oracledatabase12g.com
SQL> create table flash_maclean (t1 varchar2(200)) tablespace users;
Table created.
SQL> insert into flash_maclean values('MACLEAN LOVE HANNA');
1 row created.
SQL> commit;
Commit complete.
SQL> startup force;
ORACLE instance started.
Total System Global Area 939495424 bytes
Fixed Size 2233960 bytes
Variable Size 713034136 bytes
Database Buffers 218103808 bytes
Redo Buffers 6123520 bytes
Database mounted.
Database opened.
SQL> update flash_maclean set t1='HANNA LOVE MACLEAN';
1 row updated.
commit;
Commit complete.
SQL> alter system checkpoint;
System altered.
SQL> select dbms_rowid.rowid_block_number(rowid),dbms_rowid.rowid_relative_fno(rowid) from flash_maclean;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)
------------------------------------ ------------------------------------
140431 4
datafile 4 block 140431 对应RDBA rdba: 0x0102248f (4/140431)
SQL> ! ps -ef|grep rvwr|grep -v grep
oracle 26695 1 0 15:56 ? 00:00:00 ora_rvwr_G11R23
SQL> oradebug setospid 26695
Oracle pid: 20, Unix process pid: 26695, image: oracle@nas.oracle.com (RVWR)
SQL> ORADEBUG DUMP FBTAIL 1;
Statement processed.
To dump the last 2000 flashback records , 以上ORADEBUG DUMP FBTAIL 1命令可以转出最近2000条的闪回记录
SQL> oradebug tracefile_name
/s01/orabase/diag/rdbms/g11r23/G11R23/trace/G11R23_rvwr_26695.trc
在 TRACE文件中可以找到对应block的 before image
**** Record at fba: (lno 1 thr 1 seq 1 bno 55 bof 2564) ****
RECORD HEADER:
Type: 1 (Block Image) Size: 28
RECORD DATA (Block Image):
file#: 4 rdba: 0x0102248f
Next scn: 0x0000.00000000 [0.0]
Flag: 0x0
Block Size: 8192
BLOCK IMAGE:
buffer rdba: 0x0102248f
scn: 0x0000.00609044 seq: 0x01 flg: 0x06 tail: 0x90440601
frmt: 0x02 chkval: 0xc626 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x00002B1D94183C00 to 0x00002B1D94185C00
2B1D94183C00 0000A206 0102248F 00609044 06010000 [.....$..D.`.....]
2B1D94183C10 0000C626 00000001 00014AD4 0060903A [&........J..:.`.]
2B1D94183C20 00000000 00320002 01022488 00090006 [......2..$......]
2B1D94183C30 00000CC8 00C00340 000D0542 00008000 [....@...B.......]
2B1D94183C40 006040BC 000F000A 00000920 00C002E4 [.@`..... .......]
2B1D94183C50 0017048F 00002001 00609044 00000000 [..... ..D.`.....]
2B1D94183C60 00000000 00010100 0014FFFF 1F6E1F77 [............w.n.]
2B1D94183C70 00001F6E 1F770001 00000000 00000000 [n.....w.........]
2B1D94183C80 00000000 00000000 00000000 00000000 [................]
Repeat 500 times
2B1D94185BD0 00000000 00000000 2C000000 4D120102 [...........,...M]
2B1D94185BE0 454C4341 4C204E41 2045564F 4E4E4148 [ACLEAN LOVE HANN]
2B1D94185BF0 01002C41 43414D07 4E41454C 90440601 [A,...MACLEAN..D.]
Block header dump: 0x0102248f
Object id on Block? Y
seg/obj: 0x14ad4 csc: 0x00.60903a itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1022488 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0006.009.00000cc8 0x00c00340.0542.0d C--- 0 scn 0x0000.006040bc
0x02 0x000a.00f.00000920 0x00c002e4.048f.17 --U- 1 fsc 0x0000.00609044
bdba: 0x0102248f
data_block_dump,data header at 0x2b1d94183c64
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x2b1d94183c64
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f77
avsp=0x1f6e
tosp=0x1f6e
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1f77
block_row_dump:
tab 0, row 0, @0x1f77
tl: 22 fb: --H-FL-- lb: 0x2 cc: 1
col 0: [18] 4d 41 43 4c 45 41 4e 20 4c 4f 56 45 20 48 41 4e 4e 41
end_of_block_dump
SQL> select dump('MACLEAN LOVE HANNA',16) from dual;
DUMP('MACLEANLOVEHANNA',16)
--------------------------------------------------------------------
Typ=96 Len=18: 4d,41,43,4c,45,41,4e,20,4c,4f,56,45,20,48,41,4e,4e,41
若我们在短期内在多个事务内反复更新同样的数据块,其在flashback log中的before image版本也不会大幅增长
create table flash_maclean1 (t1 int) tablespace users;
SQL> select vs.name, ms.value
2 from v$mystat ms, v$sysstat vs
3 where vs.statistic# = ms.statistic#
4 and vs.name in ('redo size','db block changes');
NAME VALUE
---------------------------------------------------------------- ----------
db block changes 0
redo size 0
SQL> select name,value from v$sysstat where name like 'flashback log%';
NAME VALUE
---------------------------------------------------------------- ----------
flashback log writes 49
flashback log write bytes 9306112
SQL> begin
2 for i in 1..5000 loop
3 update flash_maclean1 set t1=t1+1;
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> select vs.name, ms.value
2 from v$mystat ms, v$sysstat vs
3 where vs.statistic# = ms.statistic#
4 and vs.name in ('redo size','db block changes');
NAME VALUE
---------------------------------------------------------------- ----------
db block changes 20006
redo size 3071288
SQL> select name,value from v$sysstat where name like 'flashback log%';
NAME VALUE
---------------------------------------------------------------- ----------
flashback log writes 52
flashback log write bytes 10338304
在以上的测试中可以看到 对于hot block,在产生20006 个block changes的情况下 产生了 3000k 的redo log 和 大约1000k的 flashback log 。