Oracle buffer狀態深入剖析

Davis_itpub發表於2022-03-05

Oracle buffer狀態深入剖析

oracle學習筆記 buffer狀態深入剖析

這節課把buffercache裡面的 buffer的幾個狀態給大家講一下
以對buffer有更深的瞭解

dbf的 資料塊在物理磁碟上叫block
記憶體裡面都叫buffer



一)x$bh表


資料庫中有個表x$bh

翻譯為buffer header表

這個表裡面每一行資料都對應著

buffercache裡的一個buffer



也就是每一個在buffercache的塊在x$bh裡面都有一個行和它對應

所以我們研究buffercache就研究x$bh就可以



先看一下這個表有多少列

開始老師輸出資料的格式未設定好,結果有些亂

所以要設定sql語法語句資料輸出格式

在sqlplus命令列環境提供了很多額外的非sql語法命令

其中有column



這裡老師輸入了

column name format a10

命令

是sqlplus命令列格式化輸出的常用命令之一

執行後只在執行了它的會話中生效



column主要格式化列的顯示形式

用這個命令可以更改select語句中

指定列的輸出寬度、改變預設的列標題、設定列標題的對齊方式等一些輸出格式

上面語句將在select語句中列欄位name輸出時的格式設定為文字型,且佔10個字元寬度

如果輸出超出10個字元此列會多行顯示,但仍然是每行10個字元

是為了使結果輸出工整,如果輸出結果可看,這個命令可以不用

此命令執行後,以後的執行的每個select語句,

只要輸出中有name欄位,name欄位的顯示都是10個字元寬度



但column對desc語句的輸出沒有作用

因為desc和column同樣都不屬於sql語法,是sqlplus命令列的命令

column的作用範圍是sql語法內的輸出結果



所以老師使用了前面講過的sqlplus的另一個格式化命令set linesize使結果有序

它對在sqlplus中執行的所有命令都有效



SQL> desc x$bh

 Name                                      Null?    Type

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

 ADDR                                               RAW(4)

 INDX                                               NUMBER

 INST_ID                                            NUMBER

 HLADDR                                             RAW(4)

 BLSIZ                                              NUMBER

 NXT_HASH                                           RAW(4)

 PRV_HASH                                           RAW(4)

 NXT_REPL                                           RAW(4)

 PRV_REPL                                           RAW(4)

 FLAG                                               NUMBER

 RFLAG                                              NUMBER

 SFLAG                                              NUMBER

 LRU_FLAG                                           NUMBER

 TS#                                                NUMBER

 FILE#                                              NUMBER

 DBARFIL                                            NUMBER

 DBABLK                                             NUMBER

 CLASS                                              NUMBER

 STATE                                              NUMBER

 MODE_HELD                                          NUMBER

 CHANGES                                            NUMBER

 CSTATE                                             NUMBER

 LE_ADDR                                            RAW(4)

 DIRTY_QUEUE                                        NUMBER

 SET_DS                                             RAW(4)

 OBJ                                                NUMBER

 BA                                                 RAW(4)

 CR_SCN_BAS                                         NUMBER

 CR_SCN_WRP                                         NUMBER

 CR_XID_USN                                         NUMBER

 CR_XID_SLT                                         NUMBER

 CR_XID_SQN                                         NUMBER

 CR_UBA_FIL                                         NUMBER

 CR_UBA_BLK                                         NUMBER

 CR_UBA_SEQ                                         NUMBER

 CR_UBA_REC                                         NUMBER

 CR_SFL                                             NUMBER

 CR_CLS_BAS                                         NUMBER

 CR_CLS_WRP                                         NUMBER

 LRBA_SEQ                                           NUMBER

 LRBA_BNO                                           NUMBER

 HSCN_BAS                                           NUMBER

 HSCN_WRP                                           NUMBER

 HSUB_SCN                                           NUMBER

 US_NXT                                             RAW(4)

 US_PRV                                             RAW(4)

 WA_NXT                                             RAW(4)

 WA_PRV                                             RAW(4)

 TCH                                                NUMBER

 TIM                                                NUMBER


這個表中有很多列,不可能一次研究完

有些列需要重點關注

如TCH、FLAG、RFLAG、HLADDR

這裡我們看STATE列



二)buffer的狀態


在x$bh表中STATE列

它應該是有8種值



摘自老師教案:

state:


0, FREE, no valid block image

1, XCUR, a current mode block, exclusive to this instance

2, SCUR, a current mode block, shared with other instances

3, CR, a consistent read (stale) block image

4, READ, buffer is reserved for a block being read from disk

5, MREC, a block in media recovery mode

6, IREC, a block in instance (crash) recovery mode



對它的翻譯是:

FREE(0)=還沒有使用過的塊;

XCURRENT(1)=例項以排他方式獲取的當前模式資料塊,正在被當前的instance獨佔

SCURRENT(2)=可以與其他例項共享的當前模式資料塊,正在被當前的instance共享

CR(3)=作為一致性讀映象的資料塊,永遠不會被寫入磁碟;

READING(4)=正在從磁碟讀出的資料塊;

MRECOVERY(5)=正在進行介質恢復的資料塊;

IRECOVERY(6)=正在進行例項恢復的資料塊。



我們簡單select一下

SQL> select distinct state from x$bh;


     STATE

----------

         1

         3

         0

說面目前這個表中

state只有0 1 3這三個值

只用到了三個值

說明現在資料庫中的buffer只有這三個狀態



1)free state


0號狀態是FREE

對某個buffer來講它從來沒有被用過、還沒有和block對應就是free



2)current state和cr state


XCUR SCUR CR三個理解有一定的難度

1號狀態是XCUR



假設現在要讀一個block

這個塊在buffercache裡面沒有

就把它讀到buffer中去

計算以後把它放到一個buffer裡面

這個在buffercache中的buffer就叫CUR:current塊,叫當前塊

一個block讀進一個buffer就叫current塊



current塊和cr(consistent read讀一致性)塊是有對應的



有一個a會話連線上以後對buffer塊裡的某個行進行修改

修改完了以後沒有提交

這時候b會話上來以後讀這個buffer塊

這時b想要讀這個塊這個塊又被a修改了但是還沒有提交

b不能讀到a沒有提交的修改

b就會在另外一個位置申請一個buffer塊

然後把這個塊裡面沒有修改的寫到新申請塊

已經修改的它把修改前的值在undo裡面找到

寫入新塊,構造出一個cr塊

然後b就讀cr塊

這就是cr塊



但是這個cr塊和原始block沒有對應關係

b構造這個塊以後把資料讀出來了

讀出來以後這個塊馬上就沒用了

cr塊馬上就沒有意義了



會話a操作的塊是current塊

它永遠和原始block塊是對應的,無論是修改前後

此buffer乾淨狀態和髒狀態都是current塊

cr塊是會話b要讀這個塊但這個塊不能直接讀就構造一個cr塊

這個cr塊是臨時的

讀完以後這個塊馬上就沒有意義了

馬上就可以被覆蓋了



我們修改一個塊只能修改current塊



總結

1、我們要對一個塊進行增刪改

無論在這個塊裡面增加行、刪除行還是要修改行

我們只能修改current塊只能對current塊進行處理

2、讀的時候

current塊裡面沒有未提交的操作直接讀current就可以了

current裡有未提交的,在其它會話中我們只能構造一個cr塊



3)XCUR state和SCUR state


這地方有人理解有誤,在網上各種各樣的寫法都有



current狀態還分XCUR和SCUR

X是exclusive(獨佔的)的縮寫

S是shared(共享的)的縮寫



我們講過一個資料庫一般都有一個例項

但是也有一個資料庫對應多個例項



一個資料庫對應一個例項的情況下也就是在非RAC的環境下

current永遠都用XCUR也就是隻有XCUR

因為這個buffer塊被這個例項獨佔



如果在存在RAC的環境裡面才有可能出現SCUR

RAC中有Cache Fusion(融合)即記憶體融合技術

也叫PCM:Parallel Cache Management併發記憶體管理

SCUR在Cache Fusion技術機制會用到

因為它需要和其它程式分享這個buffer塊



在單例項環境裡面

current只有一種情況就是XCUR

SCUR在非RAC環境下是沒有的



4)read state


也是資料塊的一個狀態



block要讀到記憶體裡的buffer裡面去

讀的過程中要發生物理io

物理io需要花費時間把block塊讀到buffer裡面去如讀了10ms

這個buffer在這個10ms裡面就處於一個read狀態



read state就是block正在把資料寫入到buffer裡面去



5)MREC state,IREC state


這裡

M是media(介質)

I是instance(例項)

REC是recovery(恢復)



MREC是介質恢復

IREC是例項恢復



在oracle的備份恢復中才能用到

在正常的資料庫啟動過程中或資料庫使用過程中

一般不會出現MREC state和IREC state的情況



狀態號0、1、2、3、4出現的情況比較多



6)第8種狀態write state


就是寫狀態



塊髒了時間長了以後DBWn程式會把它寫到磁碟上

把它向磁碟寫的過程,狀態就是wirte

和讀是對應的



對我們來講最經常執行的狀態是讀寫

再就是free、xcur和cr這幾種狀態



這就是與block對應的buffer的幾種狀態




三)查詢塊狀態的例子


舉一個例子

現在有個表t2

SQL> select * from t2;


        ID NAME

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

         1 xkj

         2 jiagulun


t2現在有兩個資料行



然後

SQL> alter system flush buffer_cache;


System altered.



這是將整個buffercache全部清空

這樣可以清楚的看到sql語句生成的buffer的個數和狀態

但這在生產中是比較危險的

因為你全部清空以後接著會發生大量的物理io



使用下面語句

select

o.object_name,

decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',

6,'irec',7,'write',8,'pi') state,

count(*) blocks

from x$bh b, dba_objects o

where b.obj = o.data_object_id

and o.object_name = 'T2'

group by o.object_name, state

order by blocks desc;

能查一個物件所佔用buffer的情況



我們查t2表

SQL> select

o.object_name,

decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',

  2    3    4  6,'irec',7,'write',8,'pi') state,

  5  count(*) blocks

  6  from x$bh b, dba_objects o

  7  where b.obj = o.data_object_id

  8  and o.object_name = 'T2'

  9  group by o.object_name, state

 10  order by blocks desc;


OBJECT_NAME

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

STATE     BLOCKS

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

T2

free           2



目前t2雖然佔了2個塊但是這2個狀態是free

這種佔用的塊是free的狀態很可能和剛清空了buffer_cache有關

也就是t2根本沒有佔用buffer



這種情況是一個buffer被清空了

但這個鏈的地方還掛著一個頭指向它

即使這時buffer的狀態是free state

這是它在清空的過程中不太徹底的一個表現



現在我們再來讀一下這個表

SQL> select * from t2;


        ID NAME

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

         1 xkj

         2 jiagulun



就讀t2這個表了只是讀



再執行一下

SQL> select

o.object_name,

  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',

  4  6,'irec',7,'write',8,'pi') state,

  5  count(*) blocks

  6  from x$bh b, dba_objects o

  7  where b.obj = o.data_object_id

  8  and o.object_name = 'T2'

  9  group by o.object_name, state

 10  order by blocks desc;


OBJECT_NAME

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

STATE     BLOCKS

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

T2

xcur           2


T2

free           2



結果中t2佔了兩個塊是xcur

對這個塊讀的話也是xcur

free的兩個塊不是真實的它並沒有佔用



執行語句:

SQL> update t2 set name='jiagulunoracle' where id=1;



1 row updated.

對錶進行更新



另外再啟一個會話



執行

SQL> select * from t2;


        ID NAME

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

         1 xkj

         2 jiagulun

這時應該產生cr塊了應該會產生



在查一下t2表塊的狀態

SQL> select

o.object_name,

  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',

  4  6,'irec',7,'write',8,'pi') state,

  5  count(*) blocks

  6  from x$bh b, dba_objects o

where b.obj = o.data_object_id

  7    8  and o.object_name = 'T2'

group by o.object_name, state

  9   10  order by blocks desc;


OBJECT_NAME

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

STATE     BLOCKS

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

T2

xcur           2


T2

cr             2


T2

free           1

產生了兩個cr塊

在兩個會話中查詢結果都一樣



然後在會話2中

多次執行select * from t2;

每次執行後立即查詢t2表的塊的狀態

可以看到這時對應的cr塊會有增加,

但此數值沒有無限制的增加,

用上面方法試驗了多個不同表發現每個表對應的cr塊最多隻增加到5

說明cr塊在資料讀出來以後馬上就失效了,再次查詢還要構造新的cr塊。

在查詢過程中對應cr狀態塊沒有減少,只是說明系統還沒有回收。

構造的cr塊有上限值,說明oracle系統對它有限制



db buffer中對於一個block塊預設情況下最多可以保留6個cr讀一致性塊

這個值的大小由隱藏引數_db_block_max_cr_dba決定

它的解釋是 Maximum Allowed Number of CR buffers per dba

預設值是6包含5個CR塊和1個XCUR塊



使用

SQL> show parameter _db_block_max_cr_dba

查它的值沒有結果



oracle的隱藏引數字典是 x$ksppi和x$ksppcv基表

查詢這個隱藏引數需用

SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ

FROM x$ksppi x, x$ksppcv y

WHERE x.inst_id = USERENV ('Instance')

AND y.inst_id = USERENV ('Instance')

AND x.indx = y.indx

AND x.ksppinm LIKE '%_db_block_max_cr_dba%'

語句

結果

NAME                 VALUE DESCRIB

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

_db_block_max_cr_dba 6     Maximum Allowed Number of CR buffers per dba

oracle給的值為6說明每個block塊在CBC鏈上對應最多隻能掛6個CR塊

實際測試最多有5個CR塊另外1個為XCUR塊



在執行了update命令的會話中將工作進行提交

SQL> commit;


Commit complete.



然後在兩個會話中查詢



SQL> select

o.object_name,

  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',

6,'irec',7,'write',8,'pi') state,

  4    5  count(*) blocks

  6  from x$bh b, dba_objects o

  7  where b.obj = o.data_object_id

  8  and o.object_name = 'T2'

  9  group by o.object_name, state

 10  order by blocks desc;


OBJECT_NAME

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

STATE     BLOCKS

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

T2

cr             4


T2

xcur           2

結果中還有cr塊說明它仍掛在CBC鏈上但已經失去了意義,等著被再利用。



常見的三個狀態free、cr、xcur的都有了




這節講了buffer的狀態以及如何去判斷buffer的狀態




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

相關文章