從ITL到Undo前映象提取實驗

realkid4發表於2012-02-16

 

“多版本一致讀”是Oracle資料庫的一個重要特性。Oracle中,一個資料行,如果正在進行資料塊修改操作,而且尚未提交。其他會話的使用者select的資料是該事務修改之前的資料行資料,也就是其“前映象”。這樣,Oracle中的Select操作是不會被DML事務所阻塞。

 

讀取資料塊的前映象,是基於Oracle Undo機制完成的。當一個資料塊要發生事務修改時,會將當前的資料資訊複製到Undo Segment的相應位置中。並且作為發生的事務transaction,也會關聯上對應Undo Segment中特定的位置資訊。

 

上面的過程有一個重要細節:Undo Segment的前映象寫入操作,同樣是有Redo Log Entry生成,記錄入Redo Log的。只有這樣,才能保證在進行Instance Recovery的過程中,Oracle進行事務前滾、後滾操作時,可以完全Replay Transaction

 

Select操作要檢索一個正在進行事務的資料行時,Oracle會根據該行上對應的事務對應的Undo Block AddressUBA)定位到該資料行的前映象資訊。再到Undo Tablespace中找前映象資料。

 

本文計劃從資料塊ITLInterest Transaction List)事務槽入手,層層定位,演示找到事務資料行對應前映象的過程。

 

1、環境準備

 

我們選擇10gR2資料庫,使用的環境和資料表同筆者上文《從Dump資料塊看ITL》(http://space.itpub.net/17203031/viewspace-716353)。

 

 

SQL> select * from v$version;

 

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE        10.2.0.1.0         Production

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 - Production

 

 

此時實驗資料和Trace跟蹤檔案位置如下:

 

 

SQL> select * from t;

 

        ID VNAME

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

         1 id

         2 iddf

 

SQL> select id, dbms_rowid.rowid_relative_fno(rowid) fno, dbms_rowid.rowid_block_number(rowid) bno, dbms_rowid.rowid_row_number(rowid) rowno from t;

 

        ID        FNO        BNO      ROWNO

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

         1          1      65266          0

         2          1      65266          1

 

SQL> select f_get_trace_name from dual;

F_GET_TRACE_NAME

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

C:\TOOL\ORACLE\ORACLE\PRODUCT\10.2.0\ADMIN\OTS\UDUMP\ots_ora_4524.trc

 

 

我們Dump出初始的事務ITL列表,如下:

 

 

 

--此時ITL情況

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0x0007.02a.000085d4  0x00800ca8.35fc.09  C---    0  scn 0x078c.7f2ddad3

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

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

 

 

注意:預設情況下,Oracle資料塊的ITL事務槽初始數目是2。但是在上篇的實驗中,我們實驗過三個會話事務,用於測試ITL自動延展。現在發現,擴充的ITL列表物件並沒有收縮。這說明:ITL一旦擴充,是不會回收縮減的。

 

2、事務資訊定位解析

 

首先,我們開啟一個會話進行實驗。

 

 

SQL> update t set vname='d' where id=1;

 

1 row updated

 

 

SQL> select addr, xidusn, xidslot, xidsqn, ubafil, ubablk, ubasqn, ubarec, xid from v$transaction;

 

ADDR         XIDUSN    XIDSLOT     XIDSQN     UBAFIL     UBABLK     UBASQN     UBAREC XID

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

27F8EDCC          6          9      34214          2       1762      13420         40 06000900A6850000

 

 

注意,在v$transcation中,我們是可以方便的定位到事務標記資訊和對應的Undo Segment Block資訊的。一個Oracle事務,在定位上是透過usn, slotsqn唯一確定事務。注意上面程式碼中的三個標記,我們可以從Dump出的ITL中定位到這些資訊。

 

使用dump命令將對應資料塊的資訊dump出。

 

 

 

--將資料塊DUMP

SQL> alter system dump datafile 1 block 65266;

System altered

 

--ITL片段

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0x0007.02a.000085d4  0x00800ca8.35fc.09  C---    0  scn 0x078c.7f2ddad3

0x02   0x0006.009.000085a6  0x008006e2.346c.28  ----    1  fsc 0x0000.00000000

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

 

 

注意ITL02的槽位,從LCK資訊上看,正在進行一個事務。對應的xid為“0x0006.009.000085a6”。這三個十六進位制組成的程式碼,正好標註出事務的ID編號。

 

我們可以使用to_number函式將三個片段資料進行十六進位制解析。

 

 

SQL> select to_number('0006','xxxxx') from dual;

 

TO_NUMBER('0006','XXXXX')

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

                        6  -–v$transaction中的xidusn對應

 

SQL> select to_number('009','xxxxx') from dual;

 

TO_NUMBER('009','XXXXX')

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

                       9 -–v$transaction中的xidslot對應

 

SQL> select to_number('85a6','xxxxx') from dual;

 

TO_NUMBER('85A6','XXXXX')

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

                    34214 -–v$transaction中的xidsqn對應

 

 

說明ITL02的確是對應我們會話事務。

 

從事務槽中,我們看到了UBAUndo Block Address)資訊,為“0x008006e2.346c.28”。UBA的格式解析為:dba+seq#+rec#。其中的dba為對應的資料檔案和資料塊的地址。

 

下面我們需要做的,就是定位到Undo片段的位置。

 

3Undo位置確定和前映象匯出

 

我們需要從UBA地址找到前映象儲存的物理位置,也就是Undo塊上的特定片段。首先從DBA中分析出地址。

 

 

--16進位制DBA翻譯為十進位制格式;

SQL> select to_number('8006e2','xxxxxxxx') from dual;

TO_NUMBER('8006E2','XXXXXXXX')

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

                       8390370

 

--使用dbms_utility方法實現轉換;

SQL> select dbms_utility.data_block_address_file(8390370) file_no, dbms_utility.data_block_address_block(8390370) block_no from dual;

 

   FILE_NO   BLOCK_NO

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

         2       1762

 

 

定位到Undo Block的編號是在fno=2blockno=1762的位置上。下面需要將其dump出。

 

 

 

SQL> alter system dump datafile 2 block 1762;

System altered

 

 

匯出的Undo Block格式和一般資料塊的Dump結果格式完全不相同。需要說明,一個Undo Block內部的內容可能很多,但是針對需要的前映象資訊,需要透過UBA中的seq#rec#來確定。

 

我們首先可以從dump檔案中,根據xid編號,找到事務片段。

 

 

 

**************************************************************

UNDO BLK: 

xid: 0x0006.009.000085a6  seq: 0x346c cnt: 0x28  irb: 0x28  icl: 0x0   flg: 0x0000

 

 

cnt對應的就是UBA中的rec#,而seq對應UBA中的Seq。找到片段如下:

 

 

*-----------------------------

* Rec #0x28  slt: 0x09  objn: 112888(0x0001b8f8)  objd: 112888  tblspc: 0(0x00000000)

*       Layer:  11 (Row)   opc: 1   rci 0x00  

Undo type:  Regular undo    Begin trans    Last buffer split:  No

Temp Object:  No

Tablespace Undo:  No

rdba: 0x00000000

*-----------------------------

uba: 0x008006e2.346c.27 ctl max scn: 0x078c.7f2eae5b prv tx scn: 0x078c.7f2eae65

txn start scn: scn: 0x078c.7f2eb238 logon user: 0

 prev brb: 8390369 prev bcl: 0

KDO undo record:

KTB Redo

op: 0x03  ver: 0x01 

op: Z

KDO Op code: URP row dependencies Disabled

  xtype: XA flags: 0x00000000  bdba: 0x0040fef2  hdba: 0x0040fef1

itli: 2  ispac: 0  maxfr: 4863

tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 10

ncol: 2 nnew: 1 size: 1

col  1: [ 2]  69 64

 

 

對應的col,就是前映象資料的體現。我們的update語句修改的是vname列,與col 1相對應。

 

我們可以將”69 64”翻譯為可讀格式,判斷我們的想法。

 

 

set serveroutput on;

declare

  n varchar2(10);

begin

  dbms_stats.convert_raw_value('6964',n);

  dbms_output.put_line(n);

end;

/

 

 

SQL>

 

id

 

PL/SQL procedure successfully completed

 

 

前映象取值為id,與預想相同。

 

 

4、結論

 

本文簡單介紹瞭如何從一個事務入手,找到前映象資料的基本方法。我們文中是從itl入手進行研究的,還有可以從v$transaction檢視中進行查詢UNDO地址資訊,效果相同。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-716623/,如需轉載,請註明出處,否則將追究法律責任。

相關文章