深入研究ora-01555(1)

来源:互联网 发布:淘宝会员抓取系统下载 编辑:程序博客网 时间:2024/05/22 13:16

    ORA-01555(快照过旧)问题让很多人感到十分头痛。最近我们的生产系统上也报出了ORA-01555错误。就结合这次案例将ORA-1555问题作个案例分析,并浅析产生原因和各种解决办法。

如果要了解1555错误产生的原因,就需要知道ORACLE的两个特性:

一致性读和延迟块清除。

(1)一致性读:

    当Oracle更新数据块(Data Block Oracle中最小的存储单位)时,会在两个地方记录下这一更新动作。

一个是重做段(Redo Segment),是用于数据库恢复(Recover)用的。

一个是回滚段(UNDO Segment),而回滚段是用于事务回滚(Rollback)的(我们只关心回滚段了)。

并在数据块头部标示出来是否有修改数据。一个语句在读取数据快时,如果发现这个数据块是在它读取的过程中被修改的(即开始执行读操作时并没有被修改),就不直接从数据块上读取数据,而是从相应的回滚段条目中读取数据。这就保证了最终结果应该是读操作开始时的那一时刻的快照(snapshot),而不会受到读期间其他事务的影响。这就是Oracle的一致性读,也可以叫做多版本(Multi-Versioning)。

(2)延迟块清除:

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

    而如果前面的事务在提交之前buffercache中的脏数据已经被DBwn进程写回,那么Itl中的事务标志就不会被更新,并且数据块的Itl列表也不会记录下事务的Commit SCN。后面的事务或查询语句访问该数据块时,为了检测是否需要进行一致性读(如果数据块的Itl中记录的提交事务的Commit SCN大于当前访问该数据块的SCN,则需要进行一致性读),就需要通过Undo Block Address和Transaction 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 wherea=1;

1 row updated.

SQL> alter system flush buffer_cache;

System altered.

SQL> commit;

Commit complete.

 

Dump出数据块:

 

SQL> alter system dump datafile 5 block50959;

System altered.

 

看看Dump出来的内容:

 

Block header dump:  0x00417149

 Object id on Block? Y

 seg/obj: 0x157db  csc: 0x00.2c96f3  itc: 2 flg: O  typ: 1 - DATA

    fsl: 0  fnx: 0x0 ver: 0x01

 

 Itl          Xid                  Uba        Flag  Lck        Scn/Fsc

0x01  0x0007.020.00000463 0x00c00bf5.012f.28  C---    0 scn 0x0000.002c96be

0x02  0x0008.005.0000053b 0x00c0025b.020a.27  ----    1 fsc 0x0000.00000000

bdba: 0x00417149

data_block_dump,data header at0x7fa1b9f07a5c

===============

tsiz: 0x1fa0

hsiz: 0x18

pbl: 0x7fa1b9f07a5c

    76543210

flag=--------

ntab=1

nrow=3

frre=-1

fsbo=0x18

fseo=0x1f7b

avsp=0x1f6c

tosp=0x1f6c

0xe:pti[0]      nrow=3 offs=0

0x12:pri[0]     offs=0x1f7b

0x14:pri[1]     offs=0x1f8e

0x16:pri[2]     offs=0x1f85

block_row_dump:

tab 0, row 0, @0x1f7b

tl: 10 fb: --H-FL-- lb: 0x2  cc: 2

col 0: [ 2]  c1 02

col 1: [ 3]  c2 02 10

tab 0, row 1, @0x1f8e

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 03

col 1: [ 2]  c1 03

tab 0, row 2, @0x1f85

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 04

col 1: [ 2]  c1 04

end_of_block_dump

GLOBAL CACHE ELEMENT DUMP (address:0x69ff22f8):

 id1: 0x17149 id2: 0x1 pkey: OBJ#88027 block: (1/94537)

 lock: C rls: 0x0 acq: 0x0 latch: 3

 flags: 0x21 fair: 0 recovery: 0 fpin: 'ktswh23: ktsfbkl'

 bscn: 0x0.2c96f3 bctx: (nil) write: 0 scan: 0x0

 lcp: (nil) lnk: [NULL] lch: [0x693e1a68,0x683fae28]

 seq: 21 hist: 197 48 121 113 238 180 58 143:0 208 352 197 48 121 113 238180

   58

 GCSSHADOW 0x69ff2370,3 resp[(nil),0x17149.1] pkey 88027.0

  grant 0 cvt 0 mdrole 0x0 st 0x0 lst 0x40 GRANTQ rl LOCAL

  master 1 owner 1 sid 0 remote[(nil),0] hist 0x206181030c

  history 0xc.0x6.0x4.0xc.0x6.0x4.0x0.0x0.0x0.0x0.

  cflag 0x0 sender 0 flags 0x0 replay# 0 abast (nil).x0.1 dbmap (nil)

  disk: 0x0000.00000000 write request: 0x0000.00000000

   piscn: 0x0000.00000000 sq[0x69ff2370,0x69ff2370]

  msgseq 0x0 updseq 0x0 reqids[2,0,0] infop (nil) lockseq x19f

  pkey 88027.0

   hv114 [stat 0x0, 1->1, wm 32768, RMno 0, reminc 0, dom 0]

  kjga st 0x4, step 0.0.0, cinc 2, rmno 1, flags 0x0

   lb0, hb 0, myb 15913, drmb 15913, apifrz 0

 GCSSHADOW END

2016-08-14 04:17:56.031464 : kjbmbassert[0x17149.1]

End dump data blocks tsn: 0 file#: 1 minblk94537 maxblk 94537

 

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

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

Flag:事务标志位。由于我们在提交之前将buffercache手动flush了,所以标志位为空。请注意到,我们这在commit之前DBwn已经写回了脏数据,标志为空。

各个标志的含义分别是:

C--- = transaction has been committed and lockscleaned out

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

--U- = transaction committed (maybe long ago); SCN isan upper bound

---T = transaction was still active at block cleanoutSCN

 

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

 

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

 

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

 

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 block50959;

System altered.

 

再将数据块内容dump出来:

 

Block header dump:  0x00417149

 Object id on Block? Y

 seg/obj: 0x157db  csc: 0x00.2c9847  itc: 2 flg: O  typ: 1 - DATA

    fsl: 0  fnx: 0x0 ver: 0x01

 

 Itl          Xid                  Uba         Flag Lck        Scn/Fsc

0x01  0x0007.020.00000463 0x00c00bf5.012f.28  C---    0 scn 0x0000.002c96be

0x02  0x0008.005.0000053b 0x00c0025b.020a.27  C---    0 scn0x0000.002c96f8

bdba: 0x00417149

data_block_dump,data header at0x7fec9b50aa5c

===============

tsiz: 0x1fa0

hsiz: 0x18

pbl: 0x7fec9b50aa5c

    76543210

flag=--------

ntab=1

nrow=3

frre=-1

fsbo=0x18

fseo=0x1f7b

avsp=0x1f6c

tosp=0x1f6c

0xe:pti[0]      nrow=3 offs=0

0x12:pri[0]     offs=0x1f7b

0x14:pri[1]     offs=0x1f8e

0x16:pri[2]     offs=0x1f85

block_row_dump:

tab 0, row 0, @0x1f7b

tl: 10 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 02

col 1: [ 3]  c2 02 10

tab 0, row 1, @0x1f8e

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 03

col 1: [ 2]  c1 03

tab 0, row 2, @0x1f85

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 04

col 1: [ 2]  c1 04

end_of_block_dump

 

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




下面再看看先commit后flush的情形:

drop table t_multiver;

create table t_multiver (a number, bnumber);

insert into t_multiver values (1,1);

insert into t_multiver values (2,2);

insert into t_multiver values (3,3);

commit;

update t_multiver set b=115 where a=1;

select rowid from t_multiver;

commit;

alter system flush buffer_cache;

 

SQL> selectdbms_rowid.ROWID_RELATIVE_FNO(rowid),dbms_rowid.ROWID_BLOCK_NUMBER(rowid) fromt_multiver;

 

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)

------------------------------------------------------------------------

                                   1                                94537

                                   1                                94537

                                   1                                94537


Block header dump:  0x00417149

 Object id on Block? Y

 seg/obj: 0x157dc  csc: 0x00.2c992d  itc: 2 flg: O  typ: 1 - DATA

    fsl: 0  fnx: 0x0 ver: 0x01

 

 Itl          Xid                  Uba        Flag  Lck        Scn/Fsc

0x01  0x0007.007.00000463 0x00c00bf5.012f.33  C---    0 scn 0x0000.002c9920

0x02  0x0006.002.000005d2 0x00c003aa.01b2.1d  --U-    1 fsc 0x0000.002c9934

bdba: 0x00417149

data_block_dump,data header at 0x7f19a8466a5c

===============

tsiz: 0x1fa0

hsiz: 0x18

pbl: 0x7f19a8466a5c

    76543210

flag=--------

ntab=1

nrow=3

frre=-1

fsbo=0x18

fseo=0x1f7b

avsp=0x1f6c

tosp=0x1f6c

0xe:pti[0]      nrow=3 offs=0

0x12:pri[0]     offs=0x1f7b

0x14:pri[1]     offs=0x1f8e

0x16:pri[2]     offs=0x1f85

block_row_dump:

tab 0, row 0, @0x1f7b

tl: 10 fb: --H-FL-- lb: 0x2  cc: 2

col 0: [ 2]  c1 02

col 1: [ 3]  c2 02 10

tab 0, row 1, @0x1f8e

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 03

col 1: [ 2]  c1 03

tab 0, row 2, @0x1f85

tl: 9 fb: --H-FL-- lb: 0x0  cc: 2

col 0: [ 2]  c1 04

col 1: [ 2]  c1 04

end_of_block_dump




0 0
原创粉丝点击