ORA-01555錯誤總結(一)


轉載: 原文地址:http://blog.csdn.net/oradh/article/details/25632529


這篇文章算是undo相關問題總結的補充,因爲ORA-01555錯誤與undo有着直接的關係。
ORA-01555錯誤是一種在oracle數據庫中非常常見的錯誤,甚至也可以說是一個非常經典的錯誤,只是由於oracle的發展越來越自動化(UNDO自動管理+加強),這個錯誤已經越來越少見,可能很多使用10g的DBA都沒有遇到過這個錯誤。
這個錯誤在9i之前的版本(UNDO手工管理)出現的最多,也是最常見的,甚至可以說怎麼樣處理和避免ORA-01555 錯誤是令每一個DBA曾頭痛,但是又必須面對的問題。從9i的undo自動管理,至現在的10g、11g中的undo auto tuning,使得ORA-01555錯誤越來越少,但是這個錯誤仍然不可避免,特別是那些分析型的系統中(OLTP)。

錯誤原因(一般有兩種)
  • SQL語句執行時,需要讀取UNDO(前映像數據)來構造CR數據塊,完成一致性讀取。但是在讀取undo前映像數據時發現,undo信息已經被覆蓋(undo空間循環使用),不能構造一致性讀的CR塊,拋出ORA-01555錯誤
  • SQL語句執行時,訪問到的數據塊,需要進行延遲塊清除,但是在進行延遲塊清除時,不能確定這個數據塊的事務提交時間與SQL執行開始時間的先後次序,從而拋出ORA-01555錯誤
備註:延遲塊清除是指前一個事務完成提交時(commit),由於修改塊已經刷新至磁盤等原因,未完成塊事務信息的清除(ILT,LB信息等等),在後續的SQL語句訪問該塊時,需要清除這些信息,這個動作即延遲塊清除。

第一種情況的解決方法(僅供參考)
  • 增加UNDO空間,延緩UNDO信息被覆蓋,也可以理解爲增加undo空間循環使用一次的時間。
  • 優化拋出錯誤的SQL語句,縮短SQL語句執行的時間,也可以避免語句需要訪問undo信息被覆蓋。
  • 避免頻繁的提交也是一種可行方法,不過需要改動的量較前兩個都要大。提交頻率降低後,導致undo 信息被覆蓋的可能性也降低了(oracle數據庫中未提交的undo是不可能被覆蓋),或者undo 事務表被覆蓋的可能性也降低了。
備註:針對第二中情況的解決方法,我會在下一篇文章中介紹和模擬案例。

第一種情況示例
(1)新建一個非常小的undo表空間,並設置爲不可擴展,將自動管理的undo空間切換至這個空間
SQL> create undo tablespace undo1 datafile '/u01/test/test/undo1.dbf' size 2m autoextend off;
Tablespace created.
SQL> ALTER SYSTEM SET undo_tablespace='UNDO1';
System altered.
(2)session 1中構建示例表和選取示例行 
SQL> conn dh/dh
Connected.
SQL> create table test as select object_id,object_name from dba_objects;
Table created.
SQL> SELECT
  2   dbms_rowid.rowid_object(rowid) object_id,
  3   dbms_rowid.rowid_relative_fno(rowid) REL_FNO,
  4   dbms_rowid.rowid_block_number(rowid) BLOCKNO,
  5   dbms_rowid.rowid_row_number(rowid) ROWNO,rowid,object_id,object_name
  6  FROM test WHERE object_name='EMP';
 OBJECT_ID    REL_FNO    BLOCKNO      ROWNO ROWID               OBJECT_ID
---------- ---------- ---------- ---------- ------------------ ----------
OBJECT_NAME
--------------------
     73424          4        611        201 AAAR7QAAEAAAAJjADJ      73201
EMP
SQL> select * from test where rowid='AAAR7QAAEAAAAJjADJ';
 OBJECT_ID OBJECT_NAME
---------- --------------------
     73201 EMP
(3)dump出待修改的塊,可以看到當前塊上沒有事務存在
alter system dump datafile 4 block 611;
Block header dump:  0x01000263
 Object id on Block? Y
 seg/obj: 0x11ed0  csc: 0x00.f3559  itc: 3  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1000201 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.000f3559
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
(4)在session 2中發起遊標查詢
SQL> var cur1 refcursor
SQL> begin
  2   open :cur1 for select * from test where rowid='AAAR7QAAEAAAAJjADJ';
  3  end;
  4  /
PL/SQL procedure successfully completed.
(5)在session 1中更新這一行,根據我們知道oracle的讀一致性機制,在(4)步驟中‘查詢遊標’肯定需要回滾下面這一步進行的更新!
SQL> update test set object_name='DH' where rowid='AAAR7QAAEAAAAJjADJ';--dump塊時由於沒有刷新到磁盤,dump結果沒有變化,因此這個地方更新了兩次
1 row updated.
SQL> select * from test where rowid='AAAR7QAAEAAAAJjADJ';
 OBJECT_ID OBJECT_NAME
---------- --------------------
     73201 DH
SQL> commit;
Commit complete.
SQL> update test set object_name='DH' where rowid='AAAR7QAAEAAAAJjADJ';   ------第二次更新,實驗以此爲準
1 row updated.
(6)dump這個塊,發現確實存在事務在4,611塊上。
alter system dump datafile 4 block 611;
Block header dump:  0x01000263
 Object id on Block? Y
 seg/obj: 0x11ed0  csc: 0x00.f3a21  itc: 3  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1000201 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.000f3559
0x02   0x0010.001.00000004  0x014000d4.0001.2b  C---    0  scn 0x0000.000f3a01
0x03   0x0012.003.00000005  0x014000f4.0001.01  ----    1  fsc 0x0000.00000000
bdba: 0x01000263
transaction identifier consists of:
–Undo segment number
Transaction table slot number
Sequence number or wrap#
XID = usn# . slot# . wrap# 
A UBA consists of:
Data block address (DBA) of the block
–The sequence number of the block
–The record number within the block
UBA = DBA. seq#. rec#
SQL> select dbms_utility.data_block_address_file(to_number(substr(uba,3,8),'xxxxxxxxxxx')) undo_file#,
  2         dbms_utility.data_block_address_block(to_number(substr(uba,3,8),'xxxxxxxxxxx')) blockno#,
  3         to_number(substr(uba,12,4),'xxxxxxxxx') undo_seq,
  4         to_number(substr(uba,17,2),'xxxxxxxxx') undo_record
  5    from (select '0x014000f4.0001.01' uba from dual);
UNDO_FILE#   BLOCKNO#   UNDO_SEQ UNDO_RECORD
---------- ---------- ---------- -----------
         5        244          1           1
tab 0row 201, @0x4e7
tl: 11 fb: --H-FL-- lb: 0x3  cc: 2             --lb:0x3 對應上面的第三個itl事務槽,表示這一被鎖定,即session 1中的更新操作導致
col  0: [ 4]  c3 08 21 02
col  1: [ 2]  44 48
(7)查看session 1更新的事務信息
SQL> select xidusn,xidslot,xidsqn,ubablk,ubafil,ubarec,to_char(start_scnw,'xxxxxxxx') start_scnw,  
  2  to_char(start_scnb,'xxxxxxxx') start_scnb, start_scnb+start_scnw*power(2,32) start_scn 
  3  from v$transaction;

    XIDUSN    XIDSLOT     XIDSQN     UBABLK     UBAFIL     UBAREC  START_SCNW START_SCNB    START_SCN
---------- -   ---------     ---------- ---------- -    ---------     ----------     ----------   ----------            ---------
        18          3                 5                 244              5            1                       0         f3a22                 997922
可以看到xidusn對應xid中的0x0012(十六進制轉換爲十進制後爲18),xidslot對應xid中的003,xidsqn對應xid中的00000005
uba中的52441分別對應UBAFIL、UBABLK、UBAREC
(8)dump session 1事務使用的回滾段頭和使用回滾段塊
  TRN CTL:: seq: 0x0001 chd: 0x0004 ctl: 0x0002 inc: 0x00000000 nfb: 0x0000
            mgc: 0xb000 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe)
            uba: 0x014000f4.0001.01 scn: 0x0000.000f36b8       -----0x014000f4.0001.01對應數據塊中ITL中的UBA
Version: 0x01
  FREE BLOCK POOL::
    uba: 0x00000000.0001.26 ext: 0x0  spc: 0xc6a   
    uba: 0x00000000.0000.00 ext: 0x0  spc: 0x0     
    uba: 0x00000000.0000.00 ext: 0x0  spc: 0x0     
    uba: 0x00000000.0000.00 ext: 0x0  spc: 0x0     
    uba: 0x00000000.0000.00 ext: 0x0  spc: 0x0     
  TRN TBL:: 
  index  state cflags  wrap#    uel         scn            dba            parent-xid    nub     stmt_num    cmt
  ------------------------------------------------------------------------------------------------
   0x00    9    0x00  0x0005  0x0001  0x0000.000f39c4  0x014000f3  0x0000.000.00000000  0x00000001   0x00000000  1399878011
   0x01    9    0x00  0x0005  0x0002  0x0000.000f39ce  0x014000f3  0x0000.000.00000000  0x00000001   0x00000000  1399878011
   0x02    9    0x00  0x0005  0xffff  0x0000.000f39d7  0x00000000  0x0000.000.00000000  0x00000000   0x00000000  1399878011
   0x03   10    0x80  0x0005  0x0000  0x0000.000f3a22  0x014000f4  0x0000.000.00000000  0x00000001   0x00000000  0
   0x04    9    0x00  0x0004  0x0005  0x0000.000f3722  0x014000f2  0x0000.000.00000000  0x00000001   0x00000000  1399876988
   0x05    9    0x00  0x0004  0x0006  0x0000.000f372d  0x014000f2  0x0000.000.00000000  0x00000001   0x00000000  1399876988
   0x06    9    0x00  0x0004  0x0007  0x0000.000f3736  0x014000f2  0x0000.000.00000000  0x00000001   0x00000000  1399876988
....後面的省略.....
UNDO BLK:  
xid: 0x0012.003.00000005  seq: 0x1   cnt: 0x1   irb: 0x1   icl: 0x0   flg: 0x0000 
 Rec Offset      Rec Offset      Rec Offset      Rec Offset      Rec Offset
---------------------------------------------------------------------------
0x01 0x1f64     
*-----------------------------
* Rec #0x1  slt: 0x03  objn: 73424(0x00011ed0)  objd: 73424  tblspc: 4(0x00000004)
*       Layer:  11 (Row)   opc: 1   rci 0x00   
Undo type:  Regular undo    Begin trans    Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x014000f3.0001.27 ctl max scn: 0x0000.000f35fb prv tx scn: 0x0000.000f36b8
txn start scn: scn: 0x0000.000f3a22 logon user85
 prev brb: 20971762 prev bcl: 0
KDO undo record:
KTB Redo 
op: 0x03  ver: 0x01  
compat bit4 (post-11) padding: 1
op: Z
KDO Op code: URP row dependencies Disabled
  xtype: XAxtype KDO_KDOM2 flags: 0x00000080  bdba: 0x01000263  hdba: 0x010000aa
itli: 3  ispac: 0  maxfr: 4858
tabn: 0 slot: 201(0xc9) flag: 0x2c lock0 ckix: 0
ncol: 2 nnew: 1 size0
Vector content: 
col  1: [ 2]  44 48            ---根據下面的查詢,可以知道保存的前映像數據爲‘DH',與我們實驗相符
SQL> SELECT utl_raw.cast_to_varchar2('4448'from dual;
UTL_RAW.CAST_TO_VARCHAR2('4448')
--------------------------------------------------------------------------------
DH
(9)將session 1中的事務提交,同時發現大量的更新,覆蓋前面事務使用的回滾段信息
SQL> commit;
Commit complete.
SQL> create table test1 as select object_id, object_type from dba_objects;
Table created.
SQL> update test1 set object_type='AAAAAAAAAA'  where rownum<100;
99 rows updated.
SQL> /
99 rows updated.
SQL> /
99 rows updated.
SQL> /
99 rows updated.
SQL> /
99 rows updated.
SQL> /
99 rows updated.
SQL> /
99 rows updated.
SQL> /
update test1 set object_type='AAAAAAAAAA'  where rownum<100
*
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDO1'
SQL> begin 
  2  for i in 1..10000 loop
  3   update test1 set object_type='xxxxxx' where rownum<3;
  4  commit;
  5  end loop;
  6  end;
  7  /
(10)再次dump 4,611數據塊,發現事務確實已經提交,該塊上已經不存在活動事務
Block header dump:  0x01000263
 Object id on Block? Y
 seg/obj: 0x11ed0  csc: 0x00.f4247  itc: 3  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1000201 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.000f3559
0x02   0x0010.001.00000004  0x014000d4.0001.2b  C---    0  scn 0x0000.000f3a01
0x03   0x0012.003.00000005  0x014000f4.0001.01  C---    0  scn 0x0000.000f407e
bdba: 0x01000263
(11)再次dump前面session 1第一個事務使用過的回滾段數據塊,我們發現undo信息確實已經被覆蓋
UNDO BLK:  
xid: 0x0012.001.0000001f  seq: 0x7   cnt: 0x3f  irb: 0x3f  icl: 0x0   flg: 0x0000
 
 Rec Offset      Rec Offset      Rec Offset      Rec Offset      Rec Offset
---------------------------------------------------------------------------
0x01 0x1f60     0x02 0x1f1c     0x03 0x1e74     0x04 0x1dec     0x05 0x1da8     
0x06 0x1d00     0x07 0x1c78     0x08 0x1c34     0x09 0x1b8c     0x0a 0x1b04     
0x0b 0x1ac0     0x0c 0x1a18     0x0d 0x1990     0x0e 0x194c     0x0f 0x18a4     
0x10 0x181c     0x11 0x17d8     0x12 0x1730     0x13 0x16a8     0x14 0x1664     
0x15 0x15bc     0x16 0x1534     0x17 0x14f0     0x18 0x1448     0x19 0x13c0     
0x1a 0x137c     0x1b 0x12d4     0x1c 0x124c     0x1d 0x1208     0x1e 0x1160     
0x1f 0x10d8     0x20 0x1094     0x21 0x0fec     0x22 0x0f64     0x23 0x0f20     
0x24 0x0e78     0x25 0x0df0     0x26 0x0dac     0x27 0x0d04     0x28 0x0c7c     
0x29 0x0c38     0x2a 0x0b90     0x2b 0x0b08     0x2c 0x0ac4     0x2d 0x0a1c     
0x2e 0x0994     0x2f 0x0950     0x30 0x08a8     0x31 0x0820     0x32 0x07dc     
0x33 0x0734     0x34 0x06ac     0x35 0x0668     0x36 0x05c0     0x37 0x0538     
0x38 0x04f4     0x39 0x044c     0x3a 0x03c4     0x3b 0x0380     0x3c 0x02d8     
0x3d 0x0250     0x3e 0x020c     0x3f 0x0164     
*-----------------------------
* Rec #0x1  slt: 0x0f  objn: 73428(0x00011ed4)  objd: 73428  tblspc: 4(0x00000004)
*       Layer:  11 (Row)   opc: 1   rci 0x00   
Undo type:  Regular undo    Begin trans    Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x014000f3.0007.31 ctl max scn: 0x0000.000f9d10 prv tx scn: 0x0000.000f9d31
txn start scn: scn: 0x0000.000f9f44 logon user85
 prev brb: 20971762 prev bcl: 0
KDO undo record:
KTB Redo 
op: 0x04  ver: 0x01  
compat bit4 (post-11) padding: 1
op: L  itl: xid:  0x0012.00e.0000001e uba: 0x014000f3.0007.33
                      flg: C---    lkc:  0     scn: 0x0000.000f9f3c
KDO Op code: LKR row dependencies Disabled
  xtype: XA flags: 0x00000000  bdba: 0x0100012b  hdba: 0x0100012a
itli: 2  ispac: 0  maxfr: 4858 
tabn: 0 slot: 0 to0                      ---已經不存在session 1中第一個事務的undo信息
(12)查詢session 2中的遊標,我們知道爲了讀一致性,session 2中的查詢肯定需要使用session 1中第一個事務的undo信息,但是目前undo信息已經被覆蓋,此時oracle拋出ORA-01555才錯誤
SQL> print :cur1
ERROR:
ORA-01555: snapshot too oldrollback segment number 18 with name "_SYSSMU18$"
too small

備註:dump undo段頭和undo數據塊的語法
select name from v$rollname where usn=18;
alter system dump undo header '_SYSSMU18$';
alter system dump datafile 5 block 244; 或者  alter system dump undo block '_SYSSMU18$' xid 18 3 5;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章