ITPub博客

首页 > 数据库 > Oracle > Ora-01555问题分析

Ora-01555问题分析

原创 Oracle 作者:静以致远√团团 时间:2014-07-21 15:49:30 0 删除 编辑

Ora-01555产生原因:

 

1、一致性读导致的ora-01555

当一个较长的查询执行时,查询数据过程中数据块发生了修改,并且被commit后事物量较大,undo segment被覆盖,该查询检索到被修改数据块时,为了一致性读需要去undo中查询数据块前镜像,而该undo segment已经被覆盖所以无法找到数据,此时就会报出ora-01555错误。

2、延迟块清除导致的ora-01555

当数据块被修改后存放到buffer cache中,commit之前进行块清除时使用了延迟块清除(需要清除的数据块较多,超出了buffer_cache的10%,或者在commit之前,已经有dbwr进程将buffer_cache中的数据写入dbwr,比如commit前刷新了buffer cache),被修改的数据块通过dbwr写入数据文件,而每个事务被commit之后会有一个commit scn记录在undo里,select语句发出时会有一个select scn,如果发现select检索的数据块是被延迟块清除的,会通过ITLl事物槽到undo里找对应的该数据库的commit scn,如果此时undo已经被刷新,找不到对应的该数据库的scn,会拿select scn与undo里的最小的commit scn对比,一般来说select scn都会比undo 最小commit scn大,所以会把undo中最小commit scn作为被延迟块清除的数据库的commit scn,这样虽然有真正的该数据库的commit scn不一致,但数据是一直的,所以还是安全的。但是如果真出现比较极端的,select scn比undo里最小的commit scn还要小,那就出现ora - 01555的错误了。

 

具体过程分析

为了方便演示过程,临时修改一下undo的参数:

 

SQL> create undo tablespace undotbs02 datafile '/u01/app/oracle/oradata/orcl_dup/undotbs002' size 5m autoextend off;

Tablespace created.

SQL> alter system set undo_tablespace=undotbs02 scope=spfile;

System altered.

 

SQL> alter system set undo_retention=3 ;

System altered.

undo_retention参数用来控制undo数据的保留时间,默认的是900s,此处改为3s只是为了方便测试,更加详细的讲解请参照http://blog.itpub.net/17203031/viewspace-774498

10203事件用来跟踪块的清除操作

SQL> alter system set event='10203 trace name context forever' scope=spfile;

System altered.

 

SQL> shutdown immediate;

Database closed.

Database dismounted.

ORACLE instance shut down.

 

SQL> startup

ORACLE instance started.

Total System Global Area  167772160 bytes

Fixed Size                  1218316 bytes

Variable Size              62916852 bytes

Database Buffers          100663296 bytes

Redo Buffers                2973696 bytes

Database mounted.

Database opened.

SQL> show parameter undo;

 

NAME                                 TYPE        VALUE

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

undo_management                      string      AUTO

undo_retention                       integer     3

undo_tablespace                      string      UNDOTBS02

 

SQL> conn scott/oracle

Connected.

 

SQL> create table t as select * from emp;

Table created.

 

SQL> select 

  2  rowid,

  3  dbms_rowid.rowid_relative_fno(rowid)rel_fno,

  4  dbms_rowid.rowid_block_number(rowid)blockno

  5  from t 

  6  where rownum=1;

 

ROWID                 REL_FNO    BLOCKNO

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

AAAOEDAAEAAAAIMAAA          4        524

 

/** 为了方便,scott用户会话不要中断,不然事务会自动回滚,以下测试中dump操作均使用新的会话 **/

 

一致性读导致的ora-01555

打开一个游标,执行一个查询

SQL> conn scott/oracle

Connected.

SQL> var c1 refcursor

SQL> begin

  2  open :c1 for select * from t;

  3  end;

  4  /

PL/SQL procedure successfully completed.

 

T表的第一行数据块物理位置为数据文件4数据库524,先把该数据块dump出来看看数据库的ITL状态,为了方便些了个简单sql组合

[oracle@node1 db_1]$ more dump_block.sql 

alter system dump datafile 4 block 524;

oradebug setmypid;

oradebug tracefile_name;

 

SQL> @dump_block

System altered.

Statement processed.

/u01/app/oracle/admin/orcl_dup/udump/orcl_dup_ora_4786.trc

 

Itl状态如下,此时是没有锁定信息的

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002cce0f

0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

更改该行数据,并再次dump出块信息,Itl(0x02)行被锁定

SQL> update t set sal=1234 where rownum=1;

1 row updated.

 

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002d0488

0x02   0x0005.02f.000005ae  0x00800189.05d0.04  ----    1  fsc 0x0000.00000000

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

通过Xid可以找到相应的事务信息,0005为分配的回滚段号,02f是事务槽,00000152对应wrap

 

数据的lb被指定为0x2

tab 0, row 0, @0x1cdf

tl: 38 fb: --H-FL-- lb: 0x2  cc: 8

col  0: [ 3]  c2 0d 23

col  1: [ 4]  74 65 73 74

col  2: [ 4]  74 65 73 74

col  3: [ 3]  c2 4e 5a

col  4: [ 7]  78 72 07 11 0a 37 2c

col  5: [ 4]  c3 02 18 2e

col  6: *NULL*

col  7: [ 2]  c1 0b

 

找到回滚段,转存回滚端头部信息(使用上面的方式通过导出数据块的Xid也可以推算)

 

SQL> select * from v$rollname where usn=5;

 

       USN NAME

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

         5 _SYSSMU5$

 

或者通过v$transaction,v$session,v$rollname视图查找当前的回滚段也可以

SQL> alter system dump undo header "_SYSSMU5$";

System altered.

 

SQL> alter system dump undo header "_SYSSMU5$";

System altered.

 

SQL> oradebug setmypid;

Statement processed.

 

SQL> oradebug tracefile_name;

/u01/app/oracle/admin/orcl_dup/udump/orcl_dup_ora_7539.trc

 

 

2f事务槽状态为10此时已经被使用

index  state cflags  wrap#    uel         scn            dba            parent-xid    nub     stmt_num    cmt

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

  0x2f   10    0x80  0x05ae  0x0002  0x0000.00000000  0x00800189  0x0000.000.00000000  0x00000001   0x00000000  0

 

ccott连接的会话提交update操作

SQL> commit;

Commit complete.

 

提交事务后再导出查看一下,事务槽状态已经变为9(非激活),分配提交的scn和cmt

index  state cflags  wrap#    uel         scn            dba            parent-xid    nub     stmt_num    cmt

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

0x2f    9    0x00  0x05ae  0xffff  0x0000.002d0701  0x00800189  0x0000.000.00000000  0x00000001   0x00000000  1405908462

 

此时导出数据块信息,Scn/Fsc(commit scn)变的跟undo 中的提交scn一致,并且此时数据的锁定状态并未清除

SQL> @dump_block

System altered.

 

Statement processed.

/u01/app/oracle/admin/orcl_dup/udump/orcl_dup_ora_4960.trc

 

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002d0488

0x02   0x0005.02f.000005ae  0x00800189.05d0.04  --U-    1  fsc 0x0000.002d0701

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

tab 0, row 0, @0x1ce0

tl: 37 fb: --H-FL-- lb: 0x2  cc: 8

col  0: [ 3]  c2 0d 23

col  1: [ 4]  74 65 73 74

col  2: [ 4]  74 65 73 74

col  3: [ 3]  c2 4e 5a

col  4: [ 7]  78 72 07 11 0a 37 2c

col  5: [ 3]  c2 0d 23

col  6: *NULL*

col  7: [ 2]  c1 0b

 

 

此时执行一个大一点的事务,将undo里的更新前的524的块信息覆盖

SQL> begin

  2  for i in 1..10000 loop

  3  update emp set sal=4000;

  4  rollback;

  5  end loop;

  6  end;

  7  /

 

PL/SQL procedure successfully completed.

 

此时使用之前open的cursor执行查询,将找不到undo中的前镜像

SQL> print :c1

ERROR:

ORA-01555: snapshot too old: rollback segment number 5 with name "_SYSSMU5$"

too small

no rows selected

 

延迟块清除导致的ora-01555

 

同样的打开一个游标

 

SQL> var c1 refcursor

SQL> begin

  2  open :c1 for select * from t where rownum=1;

  3  end;

  4  /

 

PL/SQL procedure successfully completed.

更新一条数据

SQL> update t set sal = 4321 where rownum=1;

1 row updated.

 

dump该数据块,事务已分配

 

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002dde90

0x02   0x0006.003.000005c2  0x00800060.03d8.21  ----    1  fsc 0x0000.00000000

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

 

dump出回滚段段头,事务槽1e已经分配

 

SQL> alter system dump undo header '_SYSSMU6$';

System altered.

 

SQL> oradebug setmypid;

Statement processed.

SQL> oradebug tracefile_name;

/u01/app/oracle/admin/orcl_dup/udump/orcl_dup_ora_7675.trc

 

index  state cflags  wrap#    uel         scn            dba            parent-xid    nub     stmt_num    cmt

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

0x03   10    0x80  0x05c2  0x0000  0x0000.002dde97  0x00800060  0x0000.000.00000000  0x00000001   0x00000000  0

 

提交事务之前,刷新buffer_cache,使用dbwr进程将被修改的数据块写入数据文件,这样被写入的数据块就使用了延迟块缓存

 

SQL> alter system flush buffer_cache;

System altered.

SQL> alter system flush buffer_cache;

System altered.

 

SQL> alter system flush buffer_cache;

System altered.

 

提交scott的事务

SQL> commit;

Commit complete.

 

此时dump出该数据块,ITL并未清除

 

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002dde90

0x02   0x0006.003.000005c2  0x00800060.03d8.21  ----    1  fsc 0x0000.00000000

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

可是此时事务槽已经标记物inactive

index  state cflags  wrap#    uel         scn            dba            parent-xid    nub     stmt_num    cmt

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

0x03    9    0x00  0x05c2  0xffff  0x0000.002de0a1  0x00800060  0x0000.000.00000000  0x00000001   0x00000000  1405911654

 

此时执行一个大的事务,覆盖undo中该块的前镜像

 

SQL> begin

  2  for i in 1..2000 loop

  3  update emp set sal=1000;

  4  rollback;

  5  end loop;

  6  end;

  7  /

 

PL/SQL procedure successfully completed.

 

SQL> /

 

PL/SQL procedure successfully completed.

 

SQL> /

 

PL/SQL procedure successfully completed.

 

此时如果对打开的cursor c1执行查询会报错:

SQL> print :c1

ERROR:

ORA-01555: snapshot too old: rollback segment number 1 with name "_SYSSMU1$"

too small

no rows selected

 

 

再次对该数据块进行访问后,会发现该数据块commit scn被更新,但是该commit scn对应的不再是上面自己的事务槽的scn,而是undo中最小commit scn

SQL> select sal from t where rownum=1;

 

       SAL

----------

      4321

 

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.002dde90

0x02   0x0006.003.000005c2  0x00800060.03d8.21  C-U-    0  scn 0x0000.002de239

0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

 

 

测试完毕,别忘了把参数改回来

SQL> alter system set undo_retention=1080 scope=both;

System altered.

 

SQL> alter system set undo_tablespace=undotbs scope=both;

System altered.

 

SQL> drop tablespace undotbs02 including contents and datafiles;

Tablespace dropped.

 

SQL> show parameter undo

 

NAME                                 TYPE        VALUE

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

undo_management                      string      AUTO

undo_retention                       integer     1080

undo_tablespace                      string      UNDOTBS

如何避免Ora-01555

1、如果自己的undo是手动管理,尽量的是rollback segment设置的一样大。

2、尽量避免SQL的运行时间过长,通过建索引,避让全盘扫描等手段来尽量减少SQL的执行时间。

3、尽量确保网络通畅,由于网络问题带来的ora-01555让dba无奈了。。。

4、cursor尽量在使用时打开,正如上面的例子,cursor长时间打开而不操作,很容易导致ora-01555错误。使用后立即关闭。

5、如果正常情况下系统undo过多,可以考虑加大undo空间。

       6、尽量使大的查询在备库上执行。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29320885/viewspace-1223886/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
每个人都有梦想,去实现吧!

注册时间:2013-11-14

  • 博文量
    164
  • 访问量
    2191474