【DB筆試面試529】在Oracle中,數據庫塊的結構有哪幾個部分?

  • 2019 年 10 月 10 日
  • 筆記

題目部分

在Oracle中,數據庫塊的結構有哪幾個部分?

答案部分

操作系統塊是操作系統讀寫的最小操作單元,也是操作系統文件的屬性之一。當創建一個Oracle數據庫時,選擇一個基於操作系統塊的整數倍大小作為Oracle數據庫塊的大小。Oracle數據庫讀寫操作則是以Oracle塊為最小單位,而非操作系統塊。

數據庫塊也稱邏輯塊或Oracle塊,它對應磁盤上一個或多個物理塊,它的大小由初始化參數DB_BLOCK_SIZE決定,可以定義數據塊為2K、4K、8K、16K、32K甚至更大,默認Oracle塊大小是8K。若一旦設置了Oracle數據塊的大小,則在整個數據庫生命期間不能被更改。使用一個合適的Oracle塊大小對於數據庫的調優是非常重要的。

OS在每次執行I/O的時候是以OS的塊為單位;Oracle在每次執行I/O的時候是以Oracle塊為單位。Oracle塊具有以下特點:

① 最小的I/O單元;

② 包含一個或多個OS塊;

③ 大小由參數DB_BLOCK_SIZE決定;

④ 數據庫創建時設置,數據庫創建後不能更改。

在Oracle中,不論數據塊中存儲的是表(TABLE)、索引(INDEX)或簇表(CLUSTER TABLE),其內部結構都是類似的。Oracle塊的結構如下圖所示:

圖 3-8 Oracle 塊結構圖

由上圖可以看出,一個Oracle塊大約由數據塊頭(包括標準內容和可變內容,Common And Variable Header)、表目錄(Table Directory)、行目錄(Row Directory)、可用空間(Free Space)和行數據(Row Data)這幾部分組成。圖中兩個箭頭表示一個數據塊中的可用空間區的容量是可變的。

l 數據塊頭(Block Header):主要包含有數據塊地址的一些基本信息(塊地址,Block Address)和段的類型(表段、索引段等)。塊頭自上而下進行增長。

l 表目錄(Table Directory):如果一個堆組織表在此數據塊中儲存了數據行,那麼該表的信息將被記錄在數據塊的表目錄中。多個表可以將行存儲在相同的塊中。

l 行目錄(Row Directory):此區域包含數據塊中存儲的數據行的信息,即每個數據行片斷(Row Piece)在行數據(Row Data)中的地址。一個數據塊中可能保存一個完整的數據行,也可能只保存數據行的一部分。當一個數據塊(Data Block)的行目錄(Row Directory)空間被使用後,即使數據行被刪除(DELETE),行目錄空間也不會被回收。舉例來說,當一個曾經包含50條記錄的數據塊被清空後,其塊頭(Header)的行目錄仍然佔用100位元組(Byte)的空間。僅在塊中插入新行時,數據庫才會重用此空間。

l 可用空間(Free Space):是指可以為以後的更新和插入操作分配的空間,大小由PCTFREE和PCTUSED兩個參數影響。可用空間位於塊的中部,允許頭和行數據空間在必要時進行增長。當插入新行或用更大的值更新現有行的列時,行數據會佔用可用空間。導致塊頭增長的事件包括:行目錄需要更多的行條目和需要的事務處理插槽數多於最初配置的數目。塊中的可用空間最初是相鄰的。但是,刪除和更新操作可能會使塊中的可用空間變成碎片。

l 行數據(Row Data):數據塊(Data Block)中行數據(Row Data)包含了表或索引的實際數據。一個數據行可以跨多個數據塊。行數據空間自下而上進行增長。

下面介紹一下與數據塊存儲相關的幾個概念。

1、 什麼是ASSM和MSSM?

段空間有兩種管理方式,分別是手動段空間管理(Manual Segment Space Management,MSSM)和自動段空間管理(Auto Segment Space Management,ASSM)。

自動段空間管理(ASSM),它首次出現在Oracle 9.2中。自由列表FREELIST被位圖所取代,它是一個二進制的數組,能夠迅速有效地管理存儲擴展和剩餘區塊(Free Block),因此能夠改善分段存儲本質。ASSM會忽略PCTUSED參數而只使用PCTFREE參數。對於MSSM而言,可以設置FREELIST、PCTUSED和PCTFREE等參數來控制如何分配和使用段中的空間。

2、 FREELIST(自由列表)

Oracle通過維護FREELIST列表來記錄或更新所有可用的數據塊。當執行INSERT語句時,Oracle首先在FREELIST列表上搜索可用的空閑數據塊,搜索成功之後將數據插入到那個空閑塊。塊在FREELIST列表中的可用性由PCTFREE參數值來決定。起初一個空塊在FREELIST列表上列出,並且會一直保留,直到空閑空間達到PCTFREE設定的值。當一個塊被使用且達到PCTFREE設定的值之後,該塊將從FREELIST列表被移除,而當數據塊的可用空間低於PCTUSED值的時候,該塊又會回收,即重新回到FREELIST列表。Oracle使用FREELIST方式以提高數據庫性能。因此,每一個INSERT操作,Oracle僅僅需要搜索FREELIST結構,而不是搜索所有數據塊。從Oracle 9i開始,引入了ASSM,它讓Oracle自動管理FREELIST。在ASSM里,Oracle使用位圖方式來標記數據塊是否可用,這種數據塊的空間管理方式比用一個列表來管理效率更高。

3、 PCTFREE(空閑率)和PCTUSED(使用率)

PCTFREE和PCTUSED這兩個參數是面試中常問到的概念。它們用來優化數據塊空間的使用,控制數據塊是否出現在FREELIST中。當創建或者更改任何錶和索引的時候,Oracle在空間控制方面使用這兩個存儲參數。

l PCTFREE:塊中保留用於UPDATE操作的空間百分比,當數據佔用的空間達到此上限時,新的數據將不能再插入到此塊中。當數據塊中的FREE空間小於PCTFREE設置的空間時,該數據塊從FREELIST中去掉,當塊由於DML操作FREE空間大於PCTUSED設置的空間時,該數據庫塊將被添加在FREELIST鏈表中。對於表和索引來說,該值默認為10%,通過查詢DBA_TABLES或DBA_INDEXES視圖的PCT_FREE列可以獲取到該屬性的值。該值適用於MSSM和ASSM。

l PCTUSED:指定塊中數據使用空間的最低百分比;用於為插入一新行數據的最小空間的百分比。這個值決定了塊的可用狀態。可用狀態的塊可以執行插入操作,不可用狀態的塊只能執行刪除和修改,可用狀態的塊被放在FREELIST中。該值只針對錶有效,默認值為40%,通過查詢DBA_TABLES視圖的PCT_USED列可以獲取到該屬性的值。該值僅適用於MSSM。

若要修改表的PCTFREE和PCTUSED的值,可以使用ALTER語句修改。需要注意的是,修改之後只對新塊起作用,若要對表中原有的塊起作用,則可以使用MOVE重新組織表,SQL語句如下所示:

ALTER TABLE T_TEST_LHR PCTFREE 20;  ALTER TABLE T_TEST_LHR MOVE;  

若要修改索引的PCTFREE的值,可以使用如下的SQL語句:

ALTER INDEX PK_TEST_LHR  REBUILD PCTFREE 20;  

下面給出一個示例:

SYS@lhrdb> CREATE TABLE TEST_BLOCK_LHR(    2    COL1 CHAR(20),    3    COL2 NUMBER) ;  Table created.  SYS@lhrdb> CREATE INDEX IND_COL1_LHR ON TEST_BLOCK_LHR(COL1);  Index created.  SYS@lhrdb> SELECT T.PCT_FREE,    2         T.PCT_USED,    3         T.INI_TRANS    4    FROM DBA_TABLES T    5   WHERE T.TABLE_NAME ='TEST_BLOCK_LHR';    PCT_FREE   PCT_USED  INI_TRANS  ---------- ---------- ----------          10         40          1  SYS@lhrdb> SELECT  T.PCT_FREE,    2                   T.ini_trans    3    FROM DBA_INDEXES T    4   WHERE T.TABLE_NAME ='TEST_BLOCK_LHR';    PCT_FREE  INI_TRANS  ---------- ----------          10          2  SYS@lhrdb> ALTER TABLE TEST_BLOCK_LHR  PCTFREE 20 PCTUSED 60;--修改表的PTCFREE和PCTUSED的值  Table altered.  SYS@lhrdb> SELECT T.PCT_FREE,    2         T.PCT_USED,    3         T.INI_TRANS    4    FROM DBA_TABLES T    5   WHERE T.TABLE_NAME ='TEST_BLOCK_LHR';    PCT_FREE   PCT_USED  INI_TRANS  ---------- ---------- ----------          20         60          1  SYS@lhrdb> ALTER TABLE TEST_BLOCK_LHR MOVE;--重新組織表  Table altered.  SYS@lhrdb> ALTER INDEX IND_COL1_LHR REBUILD PCTFREE 20;--修改索引的PTCFREE值  Index altered.  

下面詳細介紹一下數據庫塊的dump結構。首先準備如下的表:

可以看到這3行數據都在7號數據文件的第131個塊。將該數據塊dump出來:

SYS@lhrdb> ALTER SYSTEM DUMP DATAFILE 7 BLOCK 131;  System altered.  SYS@lhrdb> SELECT VALUE FROM  V$DIAG_INFO WHERE NAME LIKE '%Default%';  VALUE  --------------------------------------------------------------------------------  /oracle/app/oracle/diag/rdbms/lhrdb/lhrdb/trace/lhrdb_ora_12386484.trc  

以下是該數據塊的完整dump結果:

[LHRDB1:oracle]:/oracle/app/oracle/diag/rdbms/lhrdb/lhrdb/trace>more lhrdb_ora_12386484.trc  Trace file /oracle/app/oracle/diag/rdbms/lhrdb/lhrdb/trace/lhrdb_ora_12386484.trc  Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production  With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,  Data Mining and Real Application Testing options  ORACLE_HOME = /oracle/app/oracle/product/11.2.0/db  System name:    AIX  Node name:      LHRDB1  Release:        1  Version:        7  Machine:        00F63A614C00  Instance name: lhrdb  Redo thread mounted by this instance: 1  Oracle process number: 30  Unix process pid: 12386484, image: oracle@LHRDB1 (TNS V1-V3)    *** 2016-09-26 11:33:32.934  *** SESSION ID:(190.1277) 2016-09-26 11:33:32.934  *** CLIENT ID:() 2016-09-26 11:33:32.934  *** SERVICE NAME:(SYS$USERS) 2016-09-26 11:33:32.934  *** MODULE NAME:(sqlplus@LHRDB1 (TNS V1-V3)) 2016-09-26 11:33:32.934  *** ACTION NAME:() 2016-09-26 11:33:32.934    *** TRACE FILE RECREATED AFTER BEING REMOVED ***    Start dump data blocks tsn: 8 file#:7 minblk 131 maxblk 131  Block dump from cache:  Dump of buffer cache at level 4 for tsn=8 rdba=29360259  BH (0x700010023ff51d0) file#: 7 rdba: 0x01c00083 (7/131) class: 1 ba: 0x700010023ee4000    set: 19 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 41,22    dbwrid: 0 obj: 96380 objn: 96380 tsn: 8 afn: 7 hint: f    hash: [0x7000100627ed2a0,0x7000100627ed2a0] lru: [0x700010023ff6640,0x700010023ff5a10]    ckptq: [NULL] fileq: [NULL] objq: [0x70001005dfd2cf0,0x70001005dfd2cf0] objaq: [0x70001005dfd2ce0,0x70001005dfd2ce0]    st: XCURRENT md: NULL fpin: 'ktspbwh2: ktspfmdb' tch: 2    flags: block_written_once redo_since_read    LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1]  Block dump from disk:  buffer tsn: 8 rdba: 0x01c00083 (7/131)  scn: 0x0000.00752951 seq: 0x01 flg: 0x06 tail: 0x29510601  frmt: 0x02 chkval: 0x4235 type: 0x06=trans data  Hex dump of block: st=0, typ_found=1  Dump of memory from 0x0000000110ADCC00 to 0x0000000110ADEC00  110ADCC00 06A20000 01C00083 00752951 00000106  [.........u)Q....]  110ADCC10 42350000 01000007 0001787C 00752950  [B5........x|.u)P]  110ADCC20 00000000 00023200 01C00080 00080002  [......2.........]  110ADCC30 000009E9 00C0108B 04AC2400 20030000  [..........$. ...]  110ADCC40 00752951 00000000 00000000 00000000  [.u)Q............]  110ADCC50 00000000 00000000 00000000 00000000  [................]  110ADCC60 00000000 00010003 FFFF0018 1F801F65  [...............e]  110ADCC70 1F650000 00031F90 1F881F80 00000000  [.e..............]  110ADCC80 00000000 00000000 00000000 00000000  [................]          Repeat 501 times  110ADEBE0 00000000 2C010202 C1040163 2C010202  [....,......c,...]  110ADEBF0 C1030162 2C010202 C1020161 29510601  [...b,......a)Q..]  Block header dump:  0x01c00083   Object id on Block? Y   seg/obj: 0x1787c  csc: 0x00.752950  itc: 2  flg: E  typ: 1 - DATA       brn: 0  bdba: 0x1c00080 ver: 0x01 opc: 0       inc: 0  exflg: 0     Itl              Xid                  Uba             Flag  Lck         Scn/Fsc  0x01   0x0008.002.000009e9  0x00c0108b.04ac.24  --U-    3  fsc 0x0000.00752951  0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000  bdba: 0x01c00083  data_block_dump,data header at 0x110adcc64  ===============  tsiz: 0x1f98  hsiz: 0x18  pbl: 0x110adcc64       76543210  flag=--------  ntab=1  nrow=3  frre=-1  fsbo=0x18  fseo=0x1f80  avsp=0x1f65  tosp=0x1f65  0xe:pti[0]      nrow=3  offs=0  0x12:pri[0]     offs=0x1f90  0x14:pri[1]     offs=0x1f88  0x16:pri[2]     offs=0x1f80  block_row_dump:  tab 0, row 0, @0x1f90  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 02  col  1: [ 1]  61  tab 0, row 1, @0x1f88  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 03  col  1: [ 1]  62  tab 0, row 2, @0x1f80  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 04  col  1: [ 1]  63  end_of_block_dump  End dump data blocks tsn: 8 file#: 7 minblk 131 maxblk 131  

下面對該dump內容做詳細解說:

一、塊頭信息區

首先看頭部信息區分析:

Block dump from disk:  buffer tsn: 8 rdba: 0x01c00083 (7/131)  scn: 0x0000.00752951 seq: 0x01 flg: 0x06 tail: 0x29510601  frmt: 0x02 chkval: 0x4235 type: 0x06=trans data

① buffer tsn: 8 表示該塊對應的表空間號,這裡是8號表空間

② rdba: 0x01c00083 (7/131) 其中,rdba(relative data block address)表示相對數據塊地址,其中(7/131)表示該塊為7號數據文件第131個塊,用4個位元組32位來表示,前10位為相對數據文件號,後22位為塊號。01c00083(十六進制)=0000 0001 1100 0000 0000 0000 1000 0011(二進制),不難看出前10位(0000 0001 11)轉換成十進制就是7,後22位(00 0000 0000 0000 1000 0011)轉換成十進制就是131。rdba在數據塊中的offset是4,即rdba存在於數據塊中的第5-9位元組中(offset從0開始算),數據塊中的每個部分在數據塊中的偏移量通過BBED可以展示出來

③ scn: 0x0000.00752951 表示數據塊頭部SCN,總共佔用6個位元組,前2個位元組(0000)表示SCN Wrap,後4個位元組(00752951)表示SCN Base。如果SCN Base達到了4個位元組表示的最大值,SCN Wrap+1,SCN Base清0。在數據塊中的offset是8。這裡的SCN號為7678289

④ seq: 0x01 表示Sequence number即日誌序列號。在數據塊中的offset是14

⑤ flg: 0x06 flg即Flag,其中,0x01代表New block即新建塊;0x02代表Delayed Logging Change advanced SCN即數據塊延遲清洗推進scn和seq;0x04代表Check value即設置校驗和;0x08代表Temporary block即臨時塊。其它值都是01、02、04、08的組合。在數據塊中的offset是15

⑥ tail: 0x29510601 即tail check,存放於數據塊的最後4個位元組,用於數據塊一致性檢查。tail check的組成:SCN Base的低2個位元組+type+seq。即tail:0x32d30601=32d3+06+01

⑦ frmt: 0x02 代表塊格式。01表示Oracle 7,02表示Oracle 8+

⑧ chkval: 0x4235 代表塊檢查值。如果參數DB_BLOCK_CHECKSUM=TRUE,那麼數據塊在讀入buffer和寫回數據文件之前都要做檢查計算,如果計算值和數據塊中記錄的計算值不匹配就會標記該塊是壞塊

⑨ type: 0x06=trans data 代表塊類型,參考以下的表格:

ID

Type

01

Undo segment header

02

Undo data block

03

Save undo header

04

Save undo data block

05

Data segment header (temp, index, data and so on)

06

KTB managed data block (with ITL)

07

Temp table data block (no ITL)

08

Sort Key

09

Sort Run

10

Segment free list block

11

Data file header

二、事務列表區

Block header dump:  0x01c00083   Object id on Block? Y   seg/obj: 0x1787c  csc: 0x00.752950  itc: 2  flg: E  typ: 1 - DATA       brn: 0  bdba: 0x1c00080 ver: 0x01 opc: 0       inc: 0  exflg: 0   Itl              Xid                     Uba         Flag   Lck        Scn/Fsc  0x01   0x0008.002.000009e9  0x00c0108b.04ac.24  --U-    3  fsc 0x0000.00752951  0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000  

①、Object id on Block? Y 表示該塊是否屬於某個對象

②、seg/obj: 0x1787c 表示該數據塊中對象的OBJECT_ID。本示例dump的是表T_TESTBLOCK_20160926_LHR,下面來驗證一下:

SYS@lhrdb> select to_number('1787c','xxxxxx') from dual;  TO_NUMBER('1787C','XXXXXX')  ---------------------------                        96380  SYS@lhrdb> select object_name,object_type from dba_objects where object_id=96380;  OBJECT_NAME                  OBJECT_TYPE  ---------------------------- -------------------  T_TESTBLOCK_20160926_LHR     TABLE  

③、csc: 0x00.752950 表示SCN at last Block CleanOut,表示最後一次塊清除(Block CleanOut)時候的SCN

④、itc: 2 塊中ITL slot的數量,根據下面的ITL圖可以看出的確只有2個ITL slot

⑤、flg: E 0表示此塊被放置在自由列表(freelist)中,E指用的是ASSM

⑥、typ: 1 DATA 表示數據庫塊的類型,1表示數據,2表示索引

⑦、bdba: 0x1c00080 Block relative data block address,相對數據塊的地址

接下來的內容屬於ITL的範圍:

圖 3-9 ITL圖

ITL(Interested Transaction List,事務槽)是Oracle數據塊內部的一個組成部分,用來記錄在該塊上發生的所有事務。1個ITL可以看作是一個記錄,在一個時間,可以記錄一個事務(包括提交或者未提交事務)。當然,如果這個事務已經提交,那麼這個ITL的位置就可以被反覆使用了,因為LTL與記錄非常類似,所以,有的時候也叫ITL槽位。

ITL位於數據塊頭(Block Header),ITL事務槽由槽位號(Itl)、Xid(Transaction ID)、Uba(Undo Block Address)、Flag、Lck和Scn/Fsc幾個部分組成。Oracle的每個數據塊中都有一個或者多個事務槽,每一個對數據塊的並發訪問事務都會佔用一個事務槽。對於已經提交的事務,ITL槽位不會馬上被覆蓋,因為一致性讀可能會用到這個信息。在實現一致性讀的時候,需要從ITL獲得Undo塊地址(Uba),並從回滾段中獲得數據前鏡像(Before Image)。

當發出一條SQL語句時,Oracle會記錄下這個時刻的SCN,然後在Buffer Cache中查找需要的BLOCK,或者從磁盤上讀。當別的會話修改了數據,或者正在修改數據時,就會在相應的塊上記錄ITL,此時Oracle發現ITL中記錄的SCN大於SELECT時刻的SCN,那麼Oracle就會根據ITL中的Uba找到Undo信息獲得該BLOCK的前鏡像,然後在Buffer Cache中構造出CR(Consistent Read)塊,此時Oralce也會檢查構造出來的BLOCK中ITL記錄的SCN。如果SCN還大於SELECT時刻的SCN,那麼會一直重複構造前鏡像,然後Oracle找到前鏡像BLOCK中的ITL的SCN是否小於SELECT的SCN,同時檢查這個事務有沒有提交或者回滾。如果沒有,那麼繼續構造前鏡像,直到找到需要的BLOCK。如果在構造前鏡像的過程中所需的Undo信息被覆蓋了,那麼就會報快照過舊(ORA-01555)的錯誤。

如果一個事務一直沒有提交,那麼這個事務將一直佔用一個ITL槽位。如果這個事務已經提交,那麼,ITL槽位中還保存的有這個事務提交時候的SCN號。

ITL的個數受參數INITRANS控制,最大ITL個數受MAXTRANS控制(Oracle 10g已廢棄MAXTRANS,默認最大支持255個並發)。在一個塊內部,默認分配了2個ITL的個數。如果這個塊內還有空閑空間(Free Space),那麼Oracle是可以利用這些空閑空間並再次分配ITL。如果沒有了空閑空間,那麼這個塊會因為不能分配新的ITL可能發生ITL等待,即enq: TX – allocate ITL entry等待事件。

在並發量特別大的系統中,最好分配足夠的ITL個數,或者設置足夠的PCTFREE,保證ITL能擴展。但是,PCTFREE有可能是被行數據給消耗掉的,如UPDATE,所以,也有可能導致塊內部的空間不夠而導致ITL等待。對於表(數據塊)來說,INITRANS這個參數的默認值是1。對於索引(索引塊)來說,這個參數默認值是2。

下面詳細介紹ITL的結構:

① Itl:ITL事務槽編號,ITL事務槽號的流水編號

② Xid:代表對應的事務id(transac[X]tion identified),在回滾段事務表中有一條記錄和這個事務對應。Xid由3列使用十六進制編碼的數字列表示,分別是:Undo Segment Number + Transaction Table Slot Number + Wrap,即由undo段號+undo槽號+undo槽號的覆蓋次數三部分組成,即usn.slot.sqn,這裡0x0008.002.000009e9轉換為10進制為8.2.2537,從下邊的查詢出的結果是相對應的:

SYS@lhrdb> SELECT XIDUSN,XIDSLOT,XIDSQN,UBAFIL,UBABLK,UBASQN,UBAREC FROM V$TRANSACTION;      XIDUSN    XIDSLOT    XIDSQN     UBAFIL   UBABLK     UBASQN     UBAREC  ---------- ---------- ---------- ------- ---------- -------- ----------           8          2       2537          3        4235       1196         36  

③ Uba:即Undo Block Address,該事務對應的回滾段地址,記錄了最近一次的該記錄的前鏡像(修改前的值)。Uba組成:Undo塊地址(Undo文件號和數據塊號)+回滾序列號+回滾記錄號。多版本一致讀是Oracle保證讀操作不會被事務阻塞的重要特性。當Server Process需要查詢一個正在被事務修改,但是尚未提交的數據時,就根據ITL上的Uba定位到對應Undo前鏡像數據位置。這裡的Uba為:0x00c0108b.04ac.24,其中00c0108b(16進制)=0000 0000 1100 0000 0001 0000 1000 1011(2進制,共32位,前10位代表文件號,後22位代表數據塊號)=文件號為3,塊號為4235(10進制);04ac(16進制)=1196(10進制);24(16進制)=36(10進制)。從以下SQL可以驗證該分析:

SYS@orclasm > SELECT DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(TO_NUMBER('00c0108b','XXXXXXXXXXXXXXX')) FILE_NO, DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(TO_NUMBER('00c0108b','XXXXXXXXXXXXXXX')) BLK FROM DUAL;     FILE_NO        BLK  ---------- ----------           3       4235  

找到Undo塊後就可以使用命令「ALTER SYSTEM DUMP DATAFILE 3 BLOCK 4235;」來對該Undo塊進行dump了。Uba的值也可以從V$TRANSACTION查詢出來:

SELECT UBAFIL 回滾段文件號,UBABLK 數據塊號,UBASQN 回滾序列號,UBAREC 回滾記錄號 FROM V$TRANSACTION ; –查看UBA

④ Flag:事務標誌位,即當前事務槽的狀態信息。這個標誌位記錄了這個事務的操作狀態,各個標誌的含義分別是:

標識

簡介

—-

事務是活動的,未提交,或者在塊清除前提交事務。

C—

事務已經提交,鎖已經被清除(提交)。

-B–

包含ITL記錄的Undo數據。

–U-

事務已經提交,但是鎖還沒有清除(快速提交)。

—T

塊清除的SCN被記錄時,該事務仍然是活動的,塊上如果有已經提交的事務,那麼在clean ount的時候,塊會被進行清除,但是這個塊裏面的事務不會被清除。

C-U-

塊被延遲清除,回滾段的信息已經改寫,SCN顯示為最小的SCN,需要由回滾段重新生成,例如在提交以前,數據塊已經刷新到數據文件上。

⑤ Lck:表示這個事務所影響的行數,鎖住了幾行數據,對應有幾個行鎖。在這裡,可以看到01號事務槽Lck為3,因為該事務槽中的事務Flag為U,證明該事務已經提交,但是鎖還沒有清除。再比如對於下邊這個ITL:

Itl            Xid                       Uba         Flag    Lck        Scn/Fsc  0x01   0x0006.020.00000271  0x00800205.0257.13  C---     0         scn 0x0000.001732c4  0x02   0x0008.006.00000279  0x00800351.0278.15  ----     1         fsc 0x0000.00000000  

看到01號事務槽Lck為0,因為該事務槽中的事務Flag為C,證明該事務已經提交,鎖已經被清除,該事務槽可以被重用。02號事務槽Lck為1,是因為對第一行做了一個更新操作,並且沒有提交,Flag為「—-」說明該事務是活動的。

⑥ Scn/Fsc:Scn表示提交時的SCN。

對於一個Oracle事務來說,可以是快速提交、也可以是延遲提交,目的都是為了提高提交的速度。提交以後,Oracle需要對ITL事務槽、每一行的鎖定標記進行清除。如果是快速提交,那麼在提交的時候,會將事務表和每一個數據塊的ITL槽進行清除。但是鎖定標記可能沒有清除,等下次用到的時候再進行清除。如果是延遲提交,那麼在提交的時候,只是將事務表進行清除,並沒有對ITL事務槽進行清除,每一行的鎖定標記也沒有清除。因此,C和U的情況特別多。塊清除的過程並不包括每個行的鎖定標記的清除,主要指的是ITL的清除。

注意:

① 事務槽中首先記錄的是XID和UBA,只有在提交以後,當對這個數據塊進行CLEANOUT的時候,才會更新FLAG和SCN。因此,Oracle總是以事務表中對這個數據塊的SCN以及FLAG為準。

② 一個事務開始以後,在一個數據塊上得到一個事務槽,那麼在這個事務提交以前,這個事務槽會一直佔用,直到這個事務提交才會釋放這個事務槽。

③ 只有在已經提交以後,這個ITL事務槽中的SCN才會有數值。

④ 事務是否已經提交、事務對應的SCN,這些信息都是以回滾段事務表中的為主,事務槽中的不準確。

⑤ 事務槽中的事務ID和UBA地址是準確的。

⑥ 事務槽中的事務ID和回滾段中的事務ID肯定不是一樣的,不同回滾段中的事務ID也一定不一樣。

三、用戶數據頭區(data_block_dump)

行目錄(Row Directory)記錄了數據塊里每一行相對於起點的偏移量,Oracle正是通過行目錄找到所需的數據行。

bdba: 0x01c00083  data_block_dump,data header at 0x110adcc64  ===============  tsiz: 0x1f98  hsiz: 0x18  pbl: 0x110adcc64       76543210  flag=--------  ntab=1  nrow=3  frre=-1  fsbo=0x18  fseo=0x1f80  avsp=0x1f65  tosp=0x1f65  0xe:pti[0]      nrow=3  offs=0  0x12:pri[0]     offs=0x1f90  0x14:pri[1]     offs=0x1f88  0x16:pri[2]     offs=0x1f80  

① bdba: 0x01c00083 block dba/rdba(數據塊地址),用4個位元組32位來表示,前10位為相對數據文件號,後22位為塊號。01c00083(十六進制)=0000 0001 1100 0000 0000 0000 1000 0011(二進制),可以看到前10位(0000 0001 11)轉換成十進制就是7,後22位(00 0000 0000 0000 1000 0011)轉換成十進制就是131,即7號文件131號數據塊

② tsiz: 0x1f98 Total Data Area Size(數據區的大小,塊的總大小),轉換為10進制即8088位元組

③ hsiz: 0x18 數據塊頭大小,轉換為10進制即24位元組

④ pbl: 0x110adcc64 指向這個數據塊在內存中映像的指針

⑤ flag=——– N=pcrfree hit(clusters);F=do not put on free list;K=flushable cluster keys

⑥ ntab=1 number of tables (>1 is a cluster),塊中包含的表的個數

⑦ nrow=3 即行數,這裡表示這個表有3行數據

⑧ frre=-1 first free row index entry, -1=you have to add one(沒有創建索引)

⑨ fsbo=0x18 free space begin offset(空閑空間起始位置),叫起始空間:可以存放數據空間的起始位置(即定義了數據層中空閑空間的起始offset)

⑩ fseo=0x1f80 free space end offset(空閑空間結束位置),叫結束空間:可以存放數據空間的結束位置(即定義了數據層中空閑空間的結束offset)

⑪ avsp=0x1f65 available space in the block(可用空間),叫空閑空間:定義了數據層中空閑空間的位元組數

⑫ tosp=0x1f65 total available space when all txs commit,叫最終空閑空間:定義了ITL中事務提交後,數據層中空閑空間的位元組數

⑬ 0xe:pti[0] nrow=3 offs=0 Table directory,整個表的開始,該塊有3條記錄

⑭ 0x12:pri[0] offs=0x1f5e 第1條記錄在偏移量為0x1f5e的地方,下面兩行以此類推

⑮ 0x14:pri[1] offs=0x1f66

⑯ 0x16:pri[2] offs=0x1f80

四、用戶數據區(block_row_dump)

block_row_dump:  tab 0, row 0, @0x1f90  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 02  col  1: [ 1]  61  tab 0, row 1, @0x1f88  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 03  col  1: [ 1]  62  tab 0, row 2, @0x1f80  tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 04  col  1: [ 1]  63  end_of_block_dump  

① tab 0, row 0, @0x1f90 第一個表第一行的位置,定義了該表在行索引中的起始插槽號

② lb: 0x1 表示lock byte,行鎖標記,表示鎖定該行的這個事務在ITL的入口。0x1說明事務在該數據行上的鎖還沒清除,並且該鎖指向01號事務槽。lb: 0x0說明事務在該數據行上的鎖已經被清除,未被鎖定。lb為0x2說明未提交,存在行鎖。

③ tl: 8 表示Row Size(number of bytes plus data)

④ fb Flag Byte

K- Cluster key

H- head of row piece

D- Deleted row

F- first data piece

L- last data piece

P- First column cintinues from previous row N- Last column cintinues in next piece

當DELETE一行數據的時候,數據並不是物理地被刪除,而是把該行標記為刪除,這個時候fb應該是–HDFL–而不是原來的–H-FL–。

⑤ cc 表示number of columns in this Row piece

關於行中的數據,可以以第一行來說明一下。由於表的第2行數據為(2,'b'),所以可以使用dump函數來驗證一下。dump函數可以按指定的格式顯示輸入數據的內部表示,這裡顯示16進制:

tl: 8 fb: --H-FL-- lb: 0x1  cc: 2  col  0: [ 2]  c1 03  col  1: [ 1]  62  SYS@lhrdb> select dump(2,16),dump('b',16) from dual;    DUMP(2,16)        DUMP('B',16)  ----------------- ----------------  Typ=2 Len=2: c1,3 Typ=96 Len=1: 62  

本文選自《Oracle程序員面試筆試寶典》,作者:李華榮。