深度分析ORACLE中的塊

it_newbalance發表於2012-10-11

一直以來對“塊”的概念總是含混不清,從字面意義理解,只知道這是ORACLE存放資料的最小單位,然而它的內部世界如何呢,本人打算從今天開始連載幾篇文件,對它進行深度分析。

通過很多文件、資料,瞭解到了資料庫基本結構魚刺圖:



基本上每個物件對應一個段( Segment),只有分割槽對應多個段,這裡的物件包括table,index,partition等等,段可以跨越多個資料檔案

每個段又有多個區(extent)來組成,這些區不能跨越多個資料檔案,同時在系統使用過程中自動擴充套件。

最後是塊(block),所有的資料都是存放在塊中。為了適應作業系統,每個塊在建立資料庫的時候預設了一個大小,這個大小一般是8K,同時在9I及其以後的版本中增加了不同大小的塊引數,這將在以後的實驗中體現。先說說這個8K大小的塊,一般來說,為了使得oracle執行讀寫資料檔案的時候有一個合理的吞吐量,這裡的塊大小,都跟作業系統塊大小設為整數倍,例如ntfs格式化的磁碟檔案,每個物理塊大小為4,這裡oracle的塊大小為8,即是代表每讀取一個oracle塊,其實物理上也就是讀取了兩個作業系統塊。這裡主要指的是資料檔案存放在塊裝置上,在實際的生產環境中,大部分情況都是將資料庫安裝在裸裝置(RAW)也叫做原始分割槽之上。關於RAW將在以後進行講解。



通過上面這段文字,我們可以瞭解到ORACLE基本的儲存結構,下一篇將針對塊的大小與存放資料大小來做實驗。

上一節瞭解到了ORACLE的儲存結構,這節講一講塊的大小與資料存放之間的關係。

大家都知道了在ORACLE環境中,所有的物件都是存放在塊中,這個塊大小與存放的記錄之間到底存在怎樣的關係呢?

做一個實驗看看:

建立一個表空間test

create tablespace test datafile '/oracle/oradata/test.dbf' size 100m;

建立一個使用者

create user test identified by test default tablespace test;

建立一個表

create table test.t1 (a1 number,a2 varchar2(100));

檢查段,可以發現在這個檢視中出現了名稱為T的段,段型別為TABLE,這個段裡面分配了1個區,其中包含8個塊,大小為64K位元組。

select segment_name,blocks,extents,bytes,segment_type,tablespace_name from dba_segments where wner='TEST';

SEGMENT_NAME     BLOCKS    EXTENTS      BYTES SEGMENT_TYPE       TABLESPACE_NAME

---------- ---------- ---------- ---------- ------------------ ----------
T                   8          1      65536 TABLE              TEST

檢查區,可以發現在這個檢視中出現了一個區,區號為0,包含8個塊,大小為64K位元組。

select segment_name,segment_type,extent_id,blocks,bytes from dba_extents where wner='TEST';

SEGMENT_NAME SEGMENT_TYPE        EXTENT_ID     BLOCKS      BYTES
---------- ------------------ ---------- ---------- ----------
T          TABLE                       0          8      65536      

檢查塊,可以發現這裡沒有載入到記憶體的塊,由此斷定,在資料未寫入的時候,記憶體中並沒有存放資料的塊。

select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;

未選定行

插入10行資料,進行測試。

SQL> declare
  2  i number
  3  ;
  4  begin
  5  for i in 1..10 loop
  6  execute immediate 'insert into test.t values (:x,:y)' using i,i;
  7  end loop;
  8  end;
  9  /

PL/SQL 過程已成功完成。

再次檢視v$bh檢視,檢查記憶體中是否使用到了塊。

select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;

     FILE#     BLOCK#     CLASS# STATU        XNC       OBJD
---------- ---------- ---------- ----- ---------- ----------
         1      28089          4 xcur           0      11038
         1      28090          1 xcur           0      11038

哈哈,果然出現了資料,說明在資料插入的表的時候在記憶體中已經載入了分配的塊,同時在這些塊中寫入了資料,這裡佔用了兩個塊,塊號分別為28089,28090,其中我們可以根據CLASS#來判斷出他們屬於不同型別。

這一節緊接著上一節來說。

上一節通過實驗,我們瞭解到,塊的建立和讀取流程,不過只是針對一個會話的,現在我們來看看在一個會話中插入資料之後,同時在另外一個會話查詢資料,這樣的情況會對塊有什麼影響。

開啟一個新的會話, 然後執行如下命令

查詢表,由於插入資料的事務沒有提交,這裡在另外的會話中就看不到任何資料,深深體現了ORACLE的多版本一致性

select * from test_gao.t;

未選定行

查詢檢視v$bh,看是否有了變化

select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;

      FILE#     BLOCK#     CLASS# STATU        XNC       OBJD
---------- ---------- ---------- ----- ---------- ----------
         1      28089          4 xcur           0      11038
         1      28090          1 cr             0      11038
         1      28090          1 cr             0      11038
         1      28090          1 xcur           0      11038

果然和上一節查詢出來的結果不同,多了紅色字型標識出來的兩行,大家可以看到這兩行的STATUS欄位值為cr,什麼是cr呢?它是Consistency Read(一致性讀取)的縮寫。從這裡可以看出28090這個塊被兩個會話進行了操作。

在第一個會話中回滾事務會發生什麼呢?看下面的操作:

會話1:執行rollback

SQL> rollback;

回退已完成。

再次查詢v$bh檢視,看看什麼情況

  select file#,block#,class#,status,xnc,objd from v$bh where bjd=11038;

     FILE#     BLOCK#     CLASS# STATU        XNC       OBJD
---------- ---------- ---------- ----- ---------- ----------
         1      28089          4 xcur           0      11038
         1      28090          1 cr             0      11038
         1      28090          1 cr             0      11038
         1      28090          1 xcur           0      11038

結果還是一樣,說明在事務回滾之後,塊還是處於一致讀取的狀態。

關閉資料庫例項

SQL> shutdown immediate

資料庫已經關閉。
已經解除安裝資料庫。

重新開啟資料庫

SQL>startup

ORACLE 例程已經啟動。

Total System Global Area  253214492 bytes
Fixed Size                   454428 bytes
Variable Size             117440512 bytes
Database Buffers          134217728 bytes
Redo Buffers                1101824 bytes
資料庫裝載完畢。
資料庫已經開啟。

檢查v$bh檢視

select file#,block#,class#,status,xnc,objd from v$bh where bjd=11038;

未選定行

說明在沒有進行塊中資料的相關操作的時候,並沒有從物理檔案中提取塊到記憶體。

執行查詢或者插入、更新的SQL語句

SQL> insert into test.t values (200,200);

已建立 1 行。

再次檢查v$bh檢視

SQL> select file#,block#,class#,status,xnc,objd from v$bh where bjd=11038;

     FILE#     BLOCK#     CLASS# STATU        XNC       OBJD
---------- ---------- ---------- ----- ---------- ----------
         1      28089          4 xcur           0      11038
         1      28090          1 xcur           0      11038

總結:在沒有進行物理I/O的時候,v$bh檢視中不會出現相關的塊資訊,同時證明此檢視中存放的乃是資料檔案塊放到記憶體中的“塊”資訊。

轉儲塊資料,使用這條命令

alter system dump datafile 12 block 28090;

系統已更改。

在相應的目錄下找出trace檔案

一般trace檔案都存放在$ORACLE_BASE/admin/SID/udump目錄下,這裡我們找到剛剛轉儲的檔案o9i_ora_300.trc

開啟這個檔案,列出部分內容:

Dump file c:\oracle\admin\o9i\udump\o9i_ora_300.trc
Wed Jun 18 09:12:17 2008
ORACLE V9.2.0.4.0 - Production vsnsta=0
vsnsql=12 vsnxtr=3
Windows 2000 Version 5.1 Service Pack 2, CPU type 586
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
Windows 2000 Version 5.1 Service Pack 2, CPU type 586
Instance name: o9i

Redo thread mounted by this instance: 1

Oracle process number: 10

Windows thread id: 300, image: ORACLE.EXE

*** 2008-06-18 09:47:34.031
Start dump data blocks tsn: 0 file#: 1 minblk 28090 maxblk 28090
buffer tsn: 0 rdba: 0x00406dba (1/28090)
scn: 0x0000.000c0a29 seq: 0x01 flg: 0x00 tail: 0x0a290601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x00406dba
Object id on Block? Y
seg/obj: 0x2b1e  csc: 0x00.c0a29  itc: 2  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0009.019.000000e5  0x00801ea9.0045.0d  C---    0  scn 0x0000.000b9373
0x02   0x0006.005.000000e0  0x00804605.0051.2c  C---    0  scn 0x0000.000badb9

data_block_dump,data header at 0x347105c
===============
tsiz: 0x1fa0
hsiz: 0x26
pbl: 0x0347105c
bdba: 0x00406dba
     76543210
flag=--------
ntab=1
nrow=10
frre=4
fsbo=0x26
fseo=0x1e96
avsp=0x1f56
tosp=0x1f56
0xe:pti[0]    nrow=10    ffs=0
0x12:pri[0]    ffs=0x1eb6
0x14:pri[1]    ffs=0x1eae
0x16:pri[2]    ffs=0x1ea6
0x18:pri[3]    ffs=0x1e96
0x1a:pri[4]    sfll=5
0x1c:pri[5]    sfll=6
0x1e:pri[6]    sfll=7
0x20:pri[7]    sfll=8
0x22:pri[8]    sfll=9
0x24:pri[9]    sfll=-1
block_row_dump:
tab 0, row 0, @0x1eb6
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 1, @0x1eae
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 2, @0x1ea6
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 3, @0x1e96
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2] c1 02
col  1: [ 1]  33
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 28090 maxblk 28090

tsiz: 0x1fa0    塊大小,轉為10進位制是8096
hsiz: 0x26      頭大小,轉為10進位制是38



tab 0, row 0, @0x1eb6
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 1, @0x1eae
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 2, @0x1ea6
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  32
tab 0, row 3, @0x1e96
tl: 8 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  33

這寫資料表示了每條記錄的每個列內資料 ,紅色字型標識出來的全部一樣,說明這四行資料完全相同,只有第四條記錄(藍色標識)的那一列不同,為什麼呢?

查詢表中的資料確定答案

select * from test.t;

         A1 A2
---------- ----------
         1 2
         1 2
         1 2
         1 3

相信看了這個查詢結果,我們都能明白了,前3行資料完全一樣,第四行資料中第2列與前三行不同。

這裡的 c1 02 代表 1,32代表2,33代表3。

再來說說黃色字型,表示當前塊的第一個tab,四行資料,同時標識出了當前這行資料的指標。

@0x1eb6,@0x1eae,@0x1ea6,@0x1e96;7862,7854,7846,7830 這四個值分別對應了四條資料的指標,根據這個指標我們可以找到相應的值。

V$BH是BUFFER HEAD的檢視。其基表是X$BH,這是目前能夠找到的X$BH的說明中最新的版本:
Column     Type Description
~~~~~~     ~~~~~ ~~~~~~~~~~~
ADDR        RAW(4) Hex address of the Buffer Header.
INDX        NUMBER Buffer Header number
BUF#        NUMBER
HLADDR      RAW(4) Hash Chain Latch Address
See . ADDR

LRU_FLAG    NUMBER     8.1+ LRU flag
           KCBBHLDF   0x01     8.1  LRU Dump Flag used in debug print routine
           KCBBHLMT   0x02     8.1  moved to tail of lru (for extended stats)
           KCBBHLAL   0x04     8.1  on auxiliary list
           KCBBHLHB   0x08     8.1  hot buffer - not in cold portion of lru

FLAG        NUMBER
           KCBBHFBD   0x00001       buffer dirty
           KCBBHFAM   0x00002  7.3  about to modify; try not to start io
           KCBBHFAM   0x00002  8.0  about to modify; try not to start io
           KCBBHNAC   0x00002  8.1  notify dbwr after change
           KCBBHFMS   0x00004       modification started, no new writes
           KCBBHFBL   0x00008       block logged
           KCBBHFTD   0x00010       temporary data - no redo for changes
           KCBBHFBW   0x00020       being written; can't modify
           KCBBHFWW   0x00040       waiting for write to finish
           KCBBHFCK   0x00080  7.3  checkpoint asap
                      0x00080  8.0  not used
           KCBBHFMW   0x00080  8.1  multiple waiters when gc lock acquired
           KCBBHFRR   0x00100       recovery reading, do not reuse, being read
           KCBBHFUL   0x00200       unlink from lock element - make non-current
           KCBBHFDG   0x00400       write block & stop using for lock down grade
           KCBBHFCW   0x00800       write block for cross instance call
           KCBBHFCR   0x01000       reading from disk into KCBBHCR buffer
           KCBBHFGC   0x02000       has been gotten in current mode
           KCBBHFST   0x04000       stale - unused CR buf made from current
                      0x08000  7.3  Not used.
           KCBBHFDP   0x08000  8.0  deferred ping
           KCBBHFDP   0x08000  8.1  deferred ping
           KCBBHFDA   0x10000       Direct Access to buffer contents
           KCBBHFHD   0x20000       Hash chain Dump used in debug print routine
           KCBBHFIR   0x40000       Ignore Redo for instance recovery
           KCBBHFSQ   0x80000       sequential scan only flag
           KCBBHFNW  0x100000  7.3  Set to indicate a buffer that is NEW
                     0x100000  8.0  Not used
           KCBBHFBP  0x100000  8.1  Indicates that buffer was prefetched
           KCBBHFRW  0x200000  7.3  re-write if being written (sort)
                     0x200000  8.0  Not used
           KCBBHFFW  0x200000  8.1  Buffer has been written once
           KCBBHFFB  0x400000       buffer is "logically" flushed
           KCBBHFRS  0x800000       ReSilvered already - do not redirty
           KCBBHFKW 0x1000000  7.3  ckpt writing flag to avoid rescan */
                    0x1000000  8.0  Not used
           KCBBHDRC 0x1000000  8.1  buffer is nocache
                    0x2000000  7.3  Not used
           KCBBHFRG 0x2000000  8.0  Redo Generated since block read
           KCBBHFRG 0x2000000  8.1  Redo Generated since block read
           KCBBHFWS 0x10000000 8.0  Skipped write for checkpoint.
           KCBBHFDB 0x20000000 8.1  buffer is directly from a foreign DB
           KCBBHFAW 0x40000000 8.0  Flush after writing
           KCBBHFAW 0x40000000 8.1  Flush after writing

TS#         NUMBER 8.X Tablespace number
DBARFIL     NUMBER 8.X Relative file number of block
DBAFIL      NUMBER 7.3 File number of block
DBABLK      NUMBER Block number of block
CLASS       NUMBER See Note 33434.1

STATE       NUMBER
           KCBBHFREE         0       buffer free
           KCBBHEXLCUR       1       buffer current (and if DFS locked X)
           KCBBHSHRCUR       2       buffer current (and if DFS locked S)
           KCBBHCR           3       buffer consistant read
           KCBBHREADING      4       Being read
           KCBBHMRECOVERY    5       media recovery (current & special)
           KCBBHIRECOVERY    6       Instance recovery (somewhat special)

MODE_HELD   NUMBER     Mode buffer held in (MODE pre 7.3)
   0=KCBMNULL, KCBMSHARE, KCBMEXCL

CHANGES     NUMBER
CSTATE      NUMBER
X_TO_NULL   NUMBER   Count of PINGS out (OPS)
DIRTY_QUEUE NUMBER  You wont normally see buffers on the LRUW
LE_ADDR     RAW(4)  Lock Element address (OPS)
  SET_DS      RAW(4)  Buffer cache set this buffer is under
     OBJ         NUMBER       Data object number
TCH     NUMBER  8.1 Touch Count
TIM     NUMBER  8.1 Touch Time
  BA          RAW(4)
CR_SCN_BAS  NUMBER       Consistent Read SCN base
  CR_SCN_WRP  NUMBER       Consistent Read SCN wrap
  CR_XID_USN  NUMBER  CR XID Undo segment no
  CR_XID_SLT  NUMBER  CR XID slot
  CR_XID_SQN  NUMBER  CR XID Sequence
  CR_UBA_FIL  NUMBER  CR UBA file
  CR_UBA_BLK  NUMBER  CR UBA Block
CR_UBA_SEQ  NUMBER  CR UBA sequence
  CR_UBA_REC  NUMBER  CR UBA record
  CR_SFL      NUMBER
LRBA_SEQ    NUMBER  } Lowest RBA needed to recover block in cache
LRBA_BNO    NUMBER  }
  LRBA_BOF    NUMBER  }

  HRBA_SEQ    NUMBER  } Redo RBA to be flushed BEFORE this block
HRBA_BNO    NUMBER  } can be written out
  HRBA_BOF    NUMBER       }

RRBA_SEQ    NUMBER  } Block recovery RBA
RRBA_BNO    NUMBER  }
  RRBA_BOF    NUMBER  }
NXT_HASH    NUMBER Next buffer on this hash chain
PRV_HASH    NUMBER Previous buffer on this hash chain
NXT_LRU     NUMBER Next buffer on the LRU
PRV_LRU     NUMBER Previous buffer on the LRU
US_NXT      RAW(4)
  US_PRV      RAW(4)
  WA_NXT      RAW(4)
  WA_PRV      RAW(4)
  ACC         RAW(4)
MOD         RAW(4)




對於9.2.0.1 BH的資料結構為:

{
  kgglk                kcbbhha; /*  hash chain buffer is on  */
  ktsn                 kcbbhtsn; /*  tablespace number  */
  krdba                kcbbhrdba; /*  relative DBA  */
  ub4                  kcbbhflg; /*  flags: all changes require hash latch  */
  b1                   kcbbhst; /*  state of the buffer  */
  b1                   kcbbhmd; /*  mode owned in (KCBMNULL, KCBMSHR, KCBMEXCL)  */
  word                 kcbbhcla; /*  block class  */
  kfil                 kcbbhafn; /*  absolute file number  */
  kobjd                kcbbhobj; /*  Object # (disk )for block (if known)  */
  kobjn                kcbbhobjn; /*  dictionary object # (if known)  */
  ptr_t                kcbbhba; /*  buffer base address (set when mapped)  */
  kscn                 kcbbhdscn; /*  incremental Transactional DSCN  */
  kgglk                kcbbhus; /*  list of buffers using queue  */
  kgglk                kcbbhwa; /*  list of buffers waiting  */
  b1                   kcbbhccnt; /*  number of changes to buffer in single kcbchg()  */
  b1                   kcbbhcst; /*  change state for recovery if failure during kcbchg()  */
  kgglk                kcbbhrpl; /*  link for maintaining position on replacement chain  */
  b1                   kcbbhfoq; /*  TRUE iff the buffer is on a write list  */
  b1                   kcbbhlpf; /*  LRU latch protected flags  */
  ub2                  kcbbhtch; /*  touch count  */
  ub4                  kcbbhtim; /*  time of last touch count increment  */
  kcrda                kcbbhlrba; /*  lowest rba needed to recover block on disk  */
  kcrda                kcbbhrrba; /*  lowest rba needed to recover block in cache  */
  kcbcr                kcbbhcr; /*  consistent read fields  */
  kssob *              kcbbhrsop; /*  recovery s.o.; for recovery buffers only  */
  kcrfkd               kcbbhhfkd; /*  SCN of the highest change in the buffer  */
  ub2                  kcbbhdbc; /*  delayed block cleanout count  */
  ub2                  kcbbhssid;
  ub2                  kcbbhcqid; /*  which ckpt queue in working set buffer is  */
  kgglk                kcbbhckql; /*  link for checkpoint queue  */
  kgglk                kcbbhfql; /*  link for per-file checkpoint queue  */
  struct kcbwds *      kcbbhds; /*  system set descriptor  */
  struct kcbbh.UNK_lch_kcbbhsh UNK_lch_kcbbhsh; /*  all fields that are needed in shared mode  */
}

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

相關文章