HelloDBA [English]
搜索Internet 搜索 HelloDBABA
  Oracle技术站。email: fuyuncat@gmail.com  MSN: fuyuncat@hotmail.com   acoug  acoug 

ORA-01555错误浅析(2)

[English]

作者: fuyuncat

来源: www.HelloDBA.com

日期: 2005-09-07 14:50:12

分享到  新浪微博 腾讯微博 人人网 i贴吧 开心网 豆瓣 淘宝 推特 Facebook GMail Blogger Orkut Google Bookmarks

 

延迟块清除

再介绍一下另外一个可能产生1555错误的概念——延迟块清除(Delayed Block Cleanout)。但个人认为,如果不从字面意思上翻译,应该把它叫做延迟锁清除更加让人容易理解一些。

我们知道,当Oracle更新数据块时,会在回滚段(UNDO Segment)记录下这一更新动作。并且产生一个Cleanout SCN,在回滚段中,会产生对应的Transaction ID以及相应的数据记录镜像。并在对应的数据记录上,产生锁标志。在事务提交(commit)前,会在数据块的头部记录下这个Cleanout SCN(Csc)号、Undo Block Address(Uba)Transaction ID(Xid);并且在在对应Interested Transaction List(Itl)中设置锁标志,记录这个事务在这数据块中产生的锁的数目;同时在对应修改的数据记录上打上行级锁标志,并映射到对应的Itl去。当提交时,并不会一一清除掉所有锁标志,而是给对应的Itl打上相应标志,告诉后面访问该数据块的事务,相应的事务已经提交。这就叫做快速提交(Fast Commit)。而后面访问该数据块的的事务就先检查锁标志和对应的事务状态,如果发现前面的事务没有提交,并且要访问的数据记录被锁住了,就被阻塞;否则就清除相应的锁标志,并提交自己的锁标志,再重复以上动作。这就事延迟块清除。

而如果前面的事务在提交之前buffer cache中的脏数据已经被DBwn进程写回,那么Itl中的事务标志就不会被更新,并且数据块的Itl列表也不会记录下事务的Commit SCN。后面的事务或查询语句访问该数据块时,为了检测是否需要进行一致性读(如果数据块的Itl中记录的提交事务的Commit SCN大于当前访问该数据块的SCN,则需要进行一致性读),就需要通过Undo Block AddressTransaction ID到回滚段的事务信息表中去检查前面事务的状态和它的Commit SCN,确定是否做一致性读,最后将前面事务在该数据块上的标志做一次Cleanout

      下面就举一个例子:

      创建测试表:

SQL> create table t_multiver (a number, b number);
 
Table created.

     

插入测试数据,这时,实际上已经产生了一个对数据块修改的事务:

SQL> insert into t_multiver values (1,1);
 
1 row created.
 
SQL> insert into t_multiver values (2,2);
 
1 row created.
 
SQL> insert into t_multiver values (3,3);
 
1 row created.
 
SQL>
SQL> commit;
 
Commit complete.

 

修改记录,并且在commit之前将脏数据写回:

SQL> conn demo/demo
Connected.
SQL> update t_multiver set b=115 where a=1;
 
1 row updated.
 
SQL> alter system flush buffer_cache;
 
System altered.
 
SQL> commit;
 
Commit complete.
 

 

Dump出数据块:

SQL> alter system dump datafile 5 block 50959;
 
System altered.

 

看看Dump出来的内容:

Block header dump:  0x0140c70f
 Object id on Block? Y
 seg/obj: 0xe46c  csc: 0x00.a482a47c  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x140c709 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0012.02d.0000049c  0x02c00080.0192.0f  --U-    1  fsc 0x0000.00000000
0x02   0x000f.01b.00000533  0x02c00054.01bb.0f  C---    0  scn 0x0000.a482a3c3
 
data_block_dump,data header at 0x7505664
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x07505664
bdba: 0x0140c70f
     76543210
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f4a
avsp=0x1f62
tosp=0x1f62
0xe:pti[0] nrow=3   offs=0
0x12:pri[0]        offs=0x1f5e
0x14:pri[1]        offs=0x1f4a
0x16:pri[2]        offs=0x1f54
block_row_dump:
tab 0, row 0, @0x1f5e
tl: 10 fb: --H-FL-- lb: 0x1  cc: 2
col  0: [ 2]  c1 02
col  1: [ 3]  c2 02 10
tab 0, row 1, @0x1f4a
tl: 10 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 03
col  1: [ 3]  c2 03 17
tab 0, row 2, @0x1f54
tl: 10 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 04
col  1: [ 3]  c2 03 17
end_of_block_dump
End dump data blocks tsn: 5 file#: 5 minblk 50959 maxblk 50959

其余的内容在我们讨论的这个问题中不需要太关心,主要注意红色黑体部分和Interested Transaction Slot (ITS) 部分。

CSC:Cleanout SCN,它是在我们的insert操作事务中产生的。

Flag事务标志位。由于我们在提交之前将buffer cache手动flush了,所以标志位为空。请注意到,我们这在commit之前DBwn已经写回了脏数据,标志为空。各个标志的含义分别是:

C--- = transaction has been committed and locks cleaned out

-B-- = this undo record contains the undo for this ITL entry

--U- = transaction committed (maybe long ago); SCN is an upper bound
---T = transaction was still active at block cleanout SCN

可以看到,目前事务标志是----,这是为什么呢?请注意,上面过程在commit之前进行了buffer cache flush,也就是说,oracle进程在改写数据块时,该事务还未提交,也未回滚,所以标志为空。而假如将buffer cache flush放在commit之后,该标致就为--U-,即事务已经提交,但是相应的锁并没有清除(有兴趣可以自己做试验)。所以,看到后面的Lck位(行级锁数目)为1(因为我们修改了1条记录)。

再看每条记录中的行级锁对应Itl条目lb:都是0x1。即Itl中的第一条。

 

这时,我们重新访问该数据块:

SQL> alter system flush buffer_cache;
 
System altered.
 
SQL> conn demo/demo
Connected.
SQL> select * from t_multiver;
 
         A          B
---------- ----------
         1        115
         2        222
         3        222
 
SQL> alter system dump datafile 5 block 50959;
 
System altered.

 

再将数据块内容dump出来:

Block header dump:  0x0140c70f
 Object id on Block? Y
 seg/obj: 0xe46c  csc: 0x00.a482a4a3  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x140c709 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0012.02d.0000049c  0x02c00080.0192.0f  C---    0  scn 0x0000.a482a495
0x02   0x000f.01b.00000533  0x02c00054.01bb.0f  C---    0  scn 0x0000.a482a3c3
 
data_block_dump,data header at 0x7745664
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x07745664
bdba: 0x0140c70f
     76543210
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f4a
avsp=0x1f62
tosp=0x1f62
0xe:pti[0] nrow=3   offs=0
0x12:pri[0]        offs=0x1f5e
0x14:pri[1]        offs=0x1f4a
0x16:pri[2]        offs=0x1f54
block_row_dump:
tab 0, row 0, @0x1f5e
tl: 10 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 3]  c2 02 10
tab 0, row 1, @0x1f4a
tl: 10 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 03
col  1: [ 3]  c2 03 17
tab 0, row 2, @0x1f54
tl: 10 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 04
col  1: [ 3]  c2 03 17
end_of_block_dump
End dump data blocks tsn: 5 file#: 5 minblk 50959 maxblk 50959

 

这时,可以看到,前一事务的Itl条目中,Flag标志为已经被修改为C,即提交完毕,Commit SCN也被获得。锁也已经被清除,其锁Lck的数量也清0。相应的,各条记录的行锁对应Itl位也被清0

还是图解一下这个过程:

数据块初始状态:

 

第一个修改该数据块的事务提交后:

     

第二个访问该数据块的事务(清除了相应锁信息)

当然,如果事务进行的删除操作,或者事务回滚,又会有一些不同的情况。我会在另外一篇文章中详细的介绍一下延迟块清除这个东东。

 

Top

Copyright ©2005,HelloDBA.Com 保留一切权利

申明
by fuyuncat