oracle實驗記錄(buffer_cache分析(4)dbwr,lgwr,ckpt)

fufuh2o發表於2009-12-10

v$rowcache中有每個資料字典物件的統計資訊,找到最熱的物件,若有問題調整一般是加大shared pool
SQL> select cache#,type,parameter,gets,getmisses from v$rowcache order by gets d
esc;

    CACHE# TYPE        PARAMETER                              GETS  GETMISSES
---------- ----------- -------------------------------- ---------- ----------
        16 PARENT      dc_histogram_defs                     13947       2804
         7 PARENT      dc_users                              13923         19
        11 PARENT      dc_object_ids                         12002        624
         0 PARENT      dc_tablespaces                         8535          5
         8 PARENT      dc_objects                             5779        862
        16 SUBORDINATE dc_histogram_data                      2613        476
         2 PARENT      dc_segments                            2435        598
        17 PARENT      dc_global_oids                         2199         37
        10 PARENT      dc_usernames                           1752          8
        16 SUBORDINATE dc_histogram_data                      1592         72
         7 SUBORDINATE dc_users                                860         15

    CACHE# TYPE        PARAMETER                              GETS  GETMISSES
---------- ----------- -------------------------------- ---------- ----------
         3 PARENT      dc_rollback_segments                    548         21
         8 SUBORDINATE dc_object_grants                        383         69
        14 PARENT      dc_profiles                              76          2

CACHE# NUMBER Row cache ID number
TYPE VARCHAR2(11) Parent or subordinate row cache type
SUBORDINATE# NUMBER Subordinate set number
PARAMETER VARCHAR2(32) Name of the initialization parameter that determines the number of entries in the data dictionary cache
COUNT NUMBER Total number of entries in the cache
USAGE NUMBER Number of cache entries that contain valid data
FIXED NUMBER Number of fixed entries in the cache
GETS NUMBER Total number of requests for information on the data object
GETMISSES NUMBER Number of data requests resulting in cache misses
SCANS NUMBER Number of scan requests
SCANMISSES NUMBER Number of times a scan failed to find the data in the cache
SCANCOMPLETES NUMBER For a list of subordinate entries, the number of times the list was scanned completely
MODIFICATIONS NUMBER Number of inserts, updates, and deletions
FLUSHES NUMBER Number of times flushed to disk
DLM_REQUESTS NUMBER Number of DLM requests
DLM_CONFLICTS NUMBER Number of DLM conflicts
DLM_RELEASES NUMBER Number of DLM releases


SQL> select name,latch#,addr from v$latch_children  where name like '%row cache%
';

NAME                                                   LATCH# ADDR
-------------------------------------------------- ---------- --------
row cache objects                                         199 1F556BFC
row cache objects                                         199 1F557464
row cache objects                                         199 1F557CCC
row cache objects                                         199 1F5D7D34
row cache objects                                         199 1F5D7E9C
row cache objects                                         199 1F5D8704
row cache objects                                         199 1F5D896C
row cache objects                                         199 1F6589D4
.....................................................................

已選擇34行。

 

關於lru,lruw機制
lru:least recently used 最近最少使用list
lruw:least recently used write 既dirty list
lruw上掛的(buffer header)都是修改過但未寫入data file的(無論是否提交 只要在記憶體中變化就叫dirty block)
oracle用working set(lru+lruw 為一個working set)概念 避免多個dbwr process掃描lruw引起的爭用,每個working set由cache buffers lru chains latch(lru latch)管理,既lru latch就是一個working set,所有讀入buffer cache 的buffer header都按輪詢方式掛到working set上,當buffer cache讀入一個新block時 該塊對應的buffer header
會找一個可用的lru latch(一直找 下一個下一個的方式),直到找到為止,如果所有lru latch都找了一遍 沒有找到可用的 ,process 將等待latch free事件 v$session_wait中misses將記錄該事件,若啟動多個dbwn程式(db_writer_processes)每個dbwn對應一個不同working set(保證均勻使用dbwr)且每個dbwn只處理分給它的working set不會處理其它working set

 

深入lru機制
8i前機制很簡單,先進先出機制,例 buffer cache可以放4個block(1,2,3,4)有一個cache buffer chains和 一個lru list ,select 時需要block 1 讀入buffer cache找一個空閒位置,將對應的buffer header放入 cache buffer chains(放在這個雙向連結串列上)然後把這個buffer header掛到lru尾端,此時又一個select oracle需要block 2讀入buffer cache對應的buffer header放在lru前一個buffer header後 成為lru最尾端,然後又繼續有select所有的buffer cache空間剛好已經用完 lru表 最前端的buffer header -最後端buffer header對應的block正好是1,2,3,4(4是最新的)此時又一句select需要讀入block 5到buffer cache,現在buffer cache中有一個塊需要被替換掉(沒空間了,放塊5用),oracle按最近最少使用原則(按原則此時lru首尾有變化~~首是 4的 buffer header,尾是1的buffer header ,4 是最新最近使用的塊,而1 是最近最早使用的塊 ),此時1對應的buffer header資訊將修改其中(rdba)對應的block在記憶體中被清除,此buffer header中資訊將更新為block 5的資訊 對應的block 5讀入buffer cache,此時lru按最近最少使用的list為 5,3,4,2 (5是最新的 ,2是最舊的).這個演算法有個明顯缺點 就是 如果讀入一個新塊 只訪問一次 ,而尾端的要替換的block訪問多次了,尾端的要替換出去,而這個新block 對應的buffer header變為list中的首端(它也許很長時間就訪問一次,而替換了一個經常訪問的block)


8i後orcle最lru機制進行了優化,分別為lru,lruw新增了2個子連結串列(輔助連結串列,主連結串列)增加tch屬性(v$bh.tch,x$bh.tch)表示每個buffer header被訪問的次數(每訪問一次buffer header tch+1),例還是buffer cache可以放4個block(1,2,3,4)只有一個cache buffer chains 和一個lru(lru主連結串列+lru輔助連結串列組成的lru list)讀入第一個block 1到buffer cache對應的buffer header掛在lru輔助list 最末端 tch 為1,第2個block 2讀入buffer cache對應的buffer header 掛在前一個buffer header 後,成為lru輔助list最末端 tch為1 ,過了一會兒 buffer cache 空間用完了 (已經裝滿了 4個block) 此時lru輔助list 尾是 block 1 對應的buffer header(最早讀入的block)然後是block 2,block 3,首是block 4對應的buffer header(最近讀入的block),此時主lru list還是空的 ,此時又發生要讀入第5個block 5到buffer cache,oracle開始從lru輔助list尾部開始掃描(block 1處,最早讀入處)查詢可以替換的block.

*********************************
具體替換邏輯演算法:
1.掃描到的buffer header tch<_db_aging_hot_criteria header="">輸入 par 的值:  db_aging_hot
原值   14:   x.ksppinm like '%_&par%'
新值   14:   x.ksppinm like '%_db_aging_hot%'

NAME                           VALUE                     ISDEFAULT ISMOD      IS
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_db_aging_hot_criteria         2                         TRUE      FALSE      FA
LSE
Touch count which sends a buffer to head of replacement list


2.buffer header tch>_db_aging_hot_criteria 則不替換該buffer header中對應的block,繼續在lru輔助list 上搜尋,但若_db_aging_stay_count值<_db_aging_hot_criteria header="" tch="">=_db_aging_hot_criteri 將當前buffer header的tch值減半


SQL> /
輸入 par 的值:  db_aging_stay
原值   14:   x.ksppinm like '%_&par%'
新值   14:   x.ksppinm like '%_db_aging_stay%'

NAME                           VALUE                     ISDEFAULT ISMOD      IS
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_db_aging_stay_count           0                         TRUE      FALSE      FA
LSE
Touch count set when buffer moved to head of replacement list

可以具體寫為

if 當前buffer header tch >_db_aging_hot_criteria
 then 暫不重用
if  _db_aging_stay_count值>=_db_aging_hot_criteria then 此buffer header tch減半
else 次buffer header tch值 給db_aging_stay_count
end if
else
此塊重用
end if
例lru 尾端 buffer header tch為4 _db_aging_hot_criteria=2,_db_aging_stay_count=0,buffer header tch 4>_db_aging_hot_criteria 所以此塊暫不重用,但_db_aging_stay_count<_db_aging_hot_criteria header="" tch="">_db_aging_hot_criteria(4>2)此buffer header tch值減半變為(2),按此演算法掃描lru輔助list上的塊(這樣輪詢搜尋時候 就會清除一批塊出去)。

 

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

此時按邏輯演算法查到buffer header 對應block 1 作為被替換的 (tch<_db_aging_hot_criteria header="" lru="" tch="" buffer="" list="" headr="">,若又有新的block 要讀入bufffer cache那麼先掃描lru輔助list發現 沒有任何buffer header 則掃描lru主list 按邏輯規則選擇要替換資訊的buffer header 找到對應在記憶體中的block清除資訊,將新資訊放入buffer header tch=1 從lru主list 摘下 掛到lru輔助list(tch的引主對於lru有很大的改進,oracle 將訪問1次和訪問多次的block 對應的buffer header分開放入不同的lru list 查詢free space時從 lru輔助LIST開始 傾向於將TCH為1 只訪問一次的block換出記憶體,這是相當大的改進)

 

 

補充關於lru冷熱端
冷端可以看作是LIST的尾,熱端可以看作是 LIST的首 每次搜尋LIST 找 FREE SPACE時從 尾(冷)開始搜尋,塊第一次讀入buffer cache時放冷端(oracle通過tch 得知塊的訪問頻率決定塊的冷熱位置)
預設lru list 冷人端分別佔50%  _db_percent_hot_default 決定

SQL> /
輸入 par 的值:  db_percent_hot
原值   14:   x.ksppinm like '%_&par%'
新值   14:   x.ksppinm like '%_db_percent_hot%'

NAME                           VALUE                     ISDEFAULT ISMOD      IS
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_db_percent_hot_default        50                        TRUE      FALSE      FA
LSE
Percent of default buffer pool considered hot

 


dirty list(lruw)
dirty buffer(block)在記憶體中修改 但還為寫入資料檔案的(只要修改了記憶體中的值和存disk資料檔案上的值不一樣就是dirty buffer 與事務是否提交沒關係)
同樣dirty list擁有輔助,與主list
具體內部過程如下;
dml語句修改 已經在記憶體中的block 2 ,此時對應的buffer header在 lru 輔助LIST上 TCH1
1.對應的buffer header(block 2)從輔助lru摘下 插入lru主list 中間TCH+1=2
2.該buffer header 標記改為ping
3.更新該buffer header對應的記憶體資料塊block 2
4.完成更新後 取消buffer header中的ping標記
5.將buffer header從主lru list轉到 主lruw(dirty list )上
6.此時若還有事務更新block 2 ,則對應的buffer header再次被ping,更新block,取消buffer header中ping標記
7.dbwn啟動 scan主lruw將修改後的block2 對應的  buffer header轉移到 輔助lruw
8.dbwn 將輔助lruw上buffer header對應的 dirty block (block 2)寫入datafile
9.確認寫入disk後,原對應block 的buffer header從lruw輔助list上 轉掛到lrw輔助list 作為free 狀態 等待使用


主lruw list上只存在更新完dirty buffer對應的buffer header,or 被ping主(正修改)的block的buffer header,dbwr啟動先掃描主lruw skip ping狀態的buffer header 將更新完的 dirty buffer對應的bufffer header從lruw主list上 轉到 lruw輔助list上,scan lruw主LIST完或到達DBWN一個觸發值(_db_writer_scan_depth_pct)DBWN 轉LRU輔助LIST 上將掛在上面的buffer header 對應的dirty block寫入disk(LRUW輔助list上的buffer header 對應的dirty block要麼是 正在寫入disk,要麼是等待disk),另外buffer header掛在lruW list時先從尾端進入,dbwn scan時 從lurw list從首端開始,採用lruw分主輔的目的是將不同狀態buffer header分開.


_db_writer_scan_depth_pct(10.2.0.1已經廢棄,10.1還在使用  Description: Percentage of LRU buffers for dbwr to scan when looking for dirty )


lruw和 ckptq
2者都提供dirty block 對應的buffer header 都掛在 上面 (還有FILEQUEQUE 熱備份,tablespace offline時寫對應的資料檔案的dirty block用),checkpoint(增量or完全時)dbwn按checkpoint queque佇列中buffer header順序,依次寫出對應的dirty block,其他條件dbwn按lruw順序寫出到disk
ckptq上buffer header按block第一次被修改的時間先後順序排列,先修改的資料 在前面,同一個資料塊修改多次,在queue上只會出現一次(記錄最早修改),ckptq上buffer header還記錄dirty block第一次被修改時對應的redo record 在logfile中地址,rba redo block address,主要是為instance recovery 提供 長期的增量寫出操作

 

 

dbwn詳細觸發條件
1.process在輔助LRU,主LRU LIST上 掃描可以覆蓋的buffer header時,如果 已掃描的buffer header達到一定限度觸發dbwn

輸入 par 的值:  db_block_max_sc
原值   14:   x.ksppinm like '%_&par%'
新值   14:   x.ksppinm like '%_db_block_max_sc%'

NAME                           VALUE                     ISDEFAULT ISMOD      IS
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_db_block_max_scan_pct         40                        TRUE      FALSE      FA
LSE
Percentage of buffers to inspect when looking for free


SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag='kcbfsp';

KVITTAG                                                             KVITVAL
---------------------------------------------------------------- ----------
KVITDSC
----------------------------------------------------------------
kcbfsp                                                                   40
Max percentage of LRU list foreground can scan for free

 

表示已掃描的buffer header佔 lru list的百分比,到達時搜尋可用buffer header 的process 掛起,啟動DBWN,v$session_wait中表現為 event 'free buffer wait' ,v$sysstat 中dirty buffers inspected 值增加


2.當dbwn在主lruw上找dirty buffer等待被寫入datafile的buffer header,若找到buffer header的數量超過一定限度(_db_writer_scan_depth_pct決定)時,dbwn停止掃描,到輔助lruw上將dirty buffer寫入datafile,不過10.2.後_db_writer_scan_depth_pct 廢棄了


3.主lruw和輔lruw上dirty buffer總數超過 _db_large_dirty_queue ,啟動DBWN
輸入 par 的值:  db_large_dirty
原值   14:   x.ksppinm like '%_&par%'
新值   14:   x.ksppinm like '%_db_large_dirty%'

NAME                           VALUE                     ISDEFAULT ISMOD      IS
ADJ
------------------------------ ------------------------- --------- ---------- --
---
KSPPDESC
--------------------------------------------------------------------------------
----------------------------------------------------
_db_large_dirty_queue          25                        TRUE      FALSE      FA
LSE


SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag='kcbldq';

KVITTAG                                                             KVITVAL
---------------------------------------------------------------- ----------
KVITDSC
----------------------------------------------------------------
kcbldq                                                                   25
large dirty queue if kcbclw reaches this


Number of buffers which force dirty queue to be written ,既DIRTY  QUEUE長度超過25%,server process程式通知dbwn程式去寫dirty buffer

 

4.發生checkpoint ,incremental checkpoint和full checkpoint
5.將tablesapce offline,,readonly ,alter tablespace begin backup  觸發DBWN(按file queue上dirty buffer 寫)
6.drop table 時對應的 dirty block寫入datafile (按object queue 上dirty buffer 寫)

SQL> create table t1 (a int);

表已建立。

SQL> insert into t1 values(1);

已建立 1 行。

SQL> commit;

提交完成。

SQL> select file#,block# from (select dbms_rowid.rowid_relative_fno(rowid) file#
,dbms_rowid.rowid_block_number(rowid) block# from t1);

     FILE#     BLOCK#
---------- ----------
         1      61634


SQL> select status ,dirty from v$bh where file#=1 and block#=61634;

STATUS  D
------- -
free    N
xcur    Y~~~~~~ insert時產生的dirty block

SQL> drop table t1;

表已刪除。

SQL> select status ,dirty from v$bh where file#=1 and block#=61634;

未選定行~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~dirty block 重新整理到datafile了


7.每3S 發生一次(每3S dbwn將lru list上 dirty buffer移動到 dirty list,但並不代表將 DIRTY buffer 寫入datafile,需要dirty list達到 閥值 _db_large_dirty_queue)

 

 

instance recover
db執行時候,發生crash,記憶體中修改過的dirty buffer,但尚未寫入disk(包含提交和未提交的 )這些資料將丟失 ,oracle在下次啟動時候自動進行 instance recovery,應用redo 進行前滾,然後database open 後 進行 事務回滾,oracle用 checkpoint來縮短instance recovery時間
checkpoint


oracle為 預防instance abort不斷的定位instance recovery起點,使instance recovery恢復更快,這個恢復起點 離當前越近 表示DBWN啟動太頻繁,只有少量的dirty buffer沒有寫入disk,造成I/O有壓力,離當前越遠 要處理很多redo record,對應的dirty buffer也有很多沒有寫入disk 這樣instance recover恢復起來時間變的長
,oracle引入ckpt程式解決定位起點的這個問題(早期CKPT程式的功能由lgwr執行),ckpt與dbwn 共同合作定位instance recovery起點,這個起點oracle叫做checkpoint position存controlfile中還引入了ckptq,fileq(tablespace offline,readonly ,begin backup),objectq(10G引入的objectq,drop table時用)佇列結構都是一樣的,queue上掛的都是dirty buffer對應的buffer header,當發生檢查點DBWN從CKPTQ上將對應的dirty buffer寫入disk,寫完後對應的buffer header從ckptq上摘除下來放入lru list

CKPTQ上的buffer header按對應的block第一次被修改的時間的先後順序排序來排列的,越早修改的block 對應的buffer header 排在佇列的前面,若這個block修改多次 那麼QUEUE上只出現一次,ckptq上還記錄dirty block在 第一次修改時 產生的redo record 地址,lrba (LOW REDO BLOCK ADDRESS)既 LOW第一次修改時候對應的rba,如果這個塊再次更新又生成一條redo record,那麼第一個更新對應的RBA叫low rba,第2個更新的rba叫HIGHT RBA(HRBA),ckptq按lrba排序當發生incremetnal checkpoint時dbwn按lrba順序寫出dirty buffer 到disk,每個檢查點佇列由checkpoint queque latch保護,incremental checkpoint是一種輕量級更新 並不會改寫controfile中datafile的檢查點資訊 及資料檔案頭資訊
(只是記錄控制檔案檢查點SCN CONTROLFILE Checkpointed at scn 並根據incremental checkpoint的寫出 增進rba資訊)
SQL> select * from v$sgastat where lower(name)='checkpoint queue';

POOL         NAME                            BYTES
------------ -------------------------- ----------
shared pool  Checkpoint queue               128320~~~~~~~~~~CKPTQ存shared pool中


SQL> select name ,gets,misses from v$latch_children where name like '%checkpoint
%';

NAME                                                     GETS     MISSES
-------------------------------------------------- ---------- ----------
checkpoint queue latch                                   5063          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   5002          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                  22097          0
checkpoint queue latch                                  22412          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0

NAME                                                     GETS     MISSES
-------------------------------------------------- ---------- ----------
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0
checkpoint queue latch                                   4886          0

已選擇16行。


CKPT程式和DBWN程式合作
oracle引入ckptq 和增量檢查點後 dbwn每到一定時機觸發按 ckptq上順序寫入dirty buffer ,ckpt程式去監控ckptq長度達到一定限制時CKPT通知DBWN寫dirty buffer,ckpt程式根據引數及其I/O速度頻繁程度計算出一個target rba,dbwn將target rba之前的dirty buffer寫入disk,當ckpt通知dbwn target rba後,CKPT程式並不會等待dbwn寫完所有target  rba之前的dirty buffer,ckpt程式 還有一項重要任務 每3S檢測DBWN進度 看看寫到哪了並將新的檢查點位置記錄在controlfile,CKPT每3S 一次和觸發DBWN寫dirty buffer工作和在一起叫incremental checkpoint

 

SQL>  alter session set events 'immediate trace name buffers level 1';

會話已更改。

BH (1A7F7E0C) file#: 1 rdba: 0x004021e4 (1/8676) class: 1 ba: 1A740000
  set: 3 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 163
  dbwrid: 0 obj: 181 objn: 183 tsn: 0 afn: 1
  hash: [20189ed8,20189ed8] lru: [1a7f7f10,1a7f7db0]
  lru-flags:
  ckptq: [NULL] fileq: [NULL] objq: [1a7f7ca4,1a7f80c4]
  st: XCURRENT md: NULL tch: 1
  flags:
  LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
可以看到 各種佇列資訊 ,只有block為dirty buffer時,對應的buffer header中CKPTQ 才不為NULL,現在為NULL 表示不再ckptq,也不再fileq上
SQL> select status,dirty from v$bh where file#=1 and block#=8676;


STATUS  D
------- -
xcur    N~~~~~~~~~~~~~~~~~可以看見對應的block不是dirty 的

可以看到多了objq: [1a7f7ca4,1a7f80c4] 物件檢查點佇列 記錄物件的檢查點資訊(當drop table時 檢查點觸發 就靠這個佇列,寫於這個segment有關的dirty buffer)

SQL> select * from v$sgastat where name like '%object queue%';

POOL         NAME                            BYTES
------------ -------------------------- ----------
shared pool  object queue hash table d        3136       
shared pool  object queue hash buckets       69632
shared pool  object queue                    40880 ~~~~~~~~~~~存sga shared pool

 


 
***************************************************************************
CHECKPOINT PROGRESS RECORDS
***************************************************************************
 (size = 8180, compat size = 8180, section max = 11, section in-use = 0,
  last-recid= 0, old-recno = 0, last-recno = 0)
 (extent = 1, blkno = 2, numrecs = 11)
THREAD #1 - status:0x2 flags:0x0 dirty:76
low cache rba:(0x18.3d8f.0) on disk rba:(0x18.3e65.0)
on disk scn: 0x0000.001723fc 11/23/2009 11:25:15
resetlogs scn: 0x0000.0008297b 11/11/2009 16:12:20
heartbeat: 703666250 mount id: 1231494042

看trace中檢查點 資訊  heartbeat: 703666250 隔幾秒再次DUMP CONTROLFILE 可以看到 hearbeat變化了
low cache rba 檢查點位置,on disk rba 寫入redofile的 最後一條redo record的rba
on disk scn:最後一條redo record的SCN(已經寫入disk)


x$kcccp(kernel cache controlfile management checkpoint progress)

SQL> col "on disk rba" format a20
SQL> col LOWRBA format a10
SQL> set linesize 999
SQL> select to_number(cpdrt,'xxxxxxx'),cplrba_seq||','||cplrba_bno||','||CPLRBA_
BOF  lowrba ,CPODR_SEQ||','||CPodr_BNO||','||CPODR_BOF "on disk rba" ,CPODS,CPOD
T,CPHBT from X$KCCCP;

TO_NUMBER(CPDRT,'XXXXXXX') LOWRBA     on disk rba          CPODS            CPOD
T                     CPHBT
-------------------------- ---------- -------------------- ---------------- ----
---------------- ----------
                       275 24,42378,0 24,42764,0           1530870          11/2
3/2009 15:40:11   703670869
這個對應dump controlfile

SQL> /

TO_NUMBER(CPDRT,'XXXXXXX') LOWRBA     on disk rba          CPODS            CPOD
T                     CPHBT
-------------------------- ---------- -------------------- ---------------- ----
---------------- ----------
                       264 24,42398,0 24,42772,0           1530885          11/2
3/2009 15:40:47   703670879

~可以看到 cphbt有變化

cpdrt:checkpoint queue中 dirty block數
cpods:on disk rba 的 scn
cpodt:on disk rba的timestamp
cphbt:心跳  (每3S 變化一次)
cplrba_seq:最後一次incremental checkpoint對應的rba部分,日誌序列號
cplrba_bno:最後一次incremental checkpoint對應的rba部分,日誌塊號
CPLRBA_BOF:最後一次incremental checkpoint對應的rba部分,日誌偏移量
CPODR_SEQ:日誌尾rba,日誌序號
CPodr_BNO:日誌尾rba,日誌塊號
CPODR_BOF:日誌尾rba,日誌偏移量

checkpoint 位置:實際這個位置的表現方式是個rba,指向logfile中 對應的redo record,此位置前的redo record對應的資訊都已寫入disk,此後的redo record對應的資料塊有可能還在記憶體中,如果instance crash再次啟動db,oracle從controlfile中讀取low cache rba(這就是 檢查點位置),從此處開始應用redo record應用到on disk rba處,on disk rba是最後一條重做記錄的rba,若某條命令的redo record rba高於on disk rba 既說明這條記錄還沒寫入redo file ,crash後 不可以恢復(沒有相關redo 資訊),所以on disk rba可以認為是 instance recover中前滾操作的終點,比這個高的rba都在log buffer 中crash後不可恢復

簡單總結理解:low cache rba 就是instance recover的起點(ckpt記錄dbwn寫的進度),on disk rba就是終點(lgwr寫的進度)

控制checkpoint queue長度的parameter

1.此引數9i後廢棄,表示instance recovery時需要產生的io總數(檢視v$filestat.AVGIOTIM估算),比如oracle instance recover要求 10分鐘 恢復完成 avgiotime為500(os的io 每秒500次) 那麼將計算出來instance recover時間 =500*10*60=30000次 io在instance recover時候
所以fast_start_io_target=30000 設定為
SQL> show parameter fast_start_io_target;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------------------------
fast_start_io_target                 integer     0


2.9i後 fast_start_mttr_target 表示instance recover時間 S為單位,取值(0-3600),設定後fast_start_io_target,log_checkpoint_timeout,log_checkpoint_interval都將被取代
SQL> show parameter fast_start_mttr

NAME                                 TYPE        VALUE
------------------------------------ ----------- -----------------------------
fast_start_mttr_target               integer     0

3.log_checkpoint_timeout:表示檢查點位置和redo日誌尾之間的時間間隔(既LRBA 到on disk rba之間的時間間隔)以S為單位,default 1800S, 表示保持dirty buffer狀態的最長時間(1800 預設 沒有dirty buffer 報紙1800S中 還未寫入disk),也可以看作多少S啟動發生一次incremental checkpoint啟動dbwn

SQL> show parameter log_checkpoint_timeout

NAME                                 TYPE        VALUE
------------------------------------ ----------- ----------------------------
log_checkpoint_timeout               integer     1800


4.log_checkpoint_interval
表示檢查點位置和redo日誌尾的塊數量(OS塊為單位),(既LRBA 到on disk rba之間dirty buffer數)
SQL> show parameter log_checkpoint_inter

NAME                                 TYPE        VALUE
------------------------------------ ----------- ----------------------------
log_checkpoint_interval              integer     0


5. 90% smallest redo log ,oracle內部規定redo file末尾前90%位置設定為checkpoint position


file queue作用
oracle寫dirty buffer不一定從ckptq中寫

SQL> select * from v$sysstat where name like 'physical writes%';

STATISTIC# NAME                                CLASS      VALUE    STAT_ID
---------- ------------------------------ ---------- ---------- ----------
        62 physical writes                         8       7452 1190468109******************
        63 physical writes direct                  8          8 2699895516
        64 physical writes from cache              8       7444  163083034
        67 physical writes non checkpoint          8       2202 2602029796******************
       122 physical writes direct (lob)            8          0 3308932835
       123 physical writes direct tempora          8          0  996415569
           ry tablespace


已選擇6行。

physical writes,physical writes non checkpoint  oracle 將寫dirty buffer分類 1.檢查點寫,2不通過檢查點寫(alter tablespace offine  ,read only ,begin backup)
physical writes表示 實際的物理寫
physical writes non checkpoint 表示若沒有checkpoint的話,理論上物理寫的數量
checkpoint引起的物理寫=physical writes-physical writes non checkpoint

 


SQL> show user
USER 為 "XH"
SQL> create table t2(a int);

表已建立。

SQL> insert into t2 values(1);

已建立 1 行。

SQL> commit;

提交完成。

SQL> select * from v$sysstat where name like 'physical writes%';

STATISTIC# NAME                                CLASS      VALUE    STAT_ID
---------- ------------------------------ ---------- ---------- ----------
        62 physical writes                         8       7521 1190468109
        63 physical writes direct                  8          8 2699895516
        64 physical writes from cache              8       7513  163083034
        67 physical writes non checkpoint          8       2209 2602029796***********
       122 physical writes direct (lob)            8          0 3308932835
       123 physical writes direct tempora          8          0  996415569
           ry tablespace


已選擇6行。

SQL> alter tablespace users read only;

表空間已更改。

SQL> select * from v$sysstat where name like 'physical writes%';

STATISTIC# NAME                                CLASS      VALUE    STAT_ID
---------- ------------------------------ ---------- ---------- ----------
        62 physical writes                         8       7534 1190468109
        63 physical writes direct                  8          8 2699895516
        64 physical writes from cache              8       7526  163083034
        67 physical writes non checkpoint          8       2222 2602029796******觸發dbwn 按fileq寫的
       122 physical writes direct (lob)            8          0 3308932835
       123 physical writes direct tempora          8          0  996415569
           ry tablespace


已選擇6行。

 

 


SQL> alter tablespace users read write;

表空間已更改。

SQL> select file#,block# from (select dbms_rowid.rowid_relative_fno(rowid) file#
,dbms_rowid.rowid_block_number(rowid) block# from xh.t2);

     FILE#     BLOCK#
---------- ----------
         4       1341

SQL> select status,dirty from v$bh where file#=4 and block#=1341;

STATUS  D
------- -
free    N
xcur    N

SQL> update xh.t2 set  a=2;

已更新 1 行。

SQL> alter tablespace users read write;

表空間已更改。

SQL> select file#,block# from (select dbms_rowid.rowid_relative_fno(rowid) file#
,dbms_rowid.rowid_block_number(rowid) block# from xh.t2);

     FILE#     BLOCK#
---------- ----------
         4       1341

SQL> select status,dirty from v$bh where file#=4 and block#=1341;

STATUS  D
------- -
free    N
xcur    N

SQL> update xh.t2 set  a=2;

已更新 1 行。

SQL> select status,dirty from v$bh where file#=4 and block#=1341;

STATUS  D
------- -
cr      N
xcur    Y************************


SQL> select * from v$sysstat where name like 'physical writes%';

STATISTIC# NAME                                CLASS      VALUE    STAT_ID
---------- ------------------------------ ---------- ---------- ----------
        62 physical writes                         8       8167 1190468109**************
        63 physical writes direct                  8          8 2699895516
        64 physical writes from cache              8       8159  163083034
        67 physical writes non checkpoint          8       2274 2602029796
       122 physical writes direct (lob)            8          0 3308932835
       123 physical writes direct tempora          8          0  996415569
           ry tablespace


SQL> alter system set log_checkpoint_timeout=10;讓incremental checkpoint頻率發生多些

系統已更改。


SQL> /

STATUS  D
------- -
cr      N
xcur    N*********剛才的dirty buffer(update xh.t2) 已經寫入disk

SQL>

SQL> select * from v$sysstat where name like 'physical writes%';

STATISTIC# NAME                                CLASS      VALUE    STAT_ID
---------- ------------------------------ ---------- ---------- ----------
        62 physical writes                         8       8256 1190468109*************incremental checkpoint觸發dbwr用的ckptq
        63 physical writes direct                  8          8 2699895516
        64 physical writes from cache              8       8248  163083034
        67 physical writes non checkpoint          8       2277 2602029796
       122 physical writes direct (lob)            8          0 3308932835
       123 physical writes direct tempora          8          0  996415569
           ry tablespace

SQL> alter system reset log_checkpoint_timeout scope=spfile sid='*';

系統已更改。

 


SQL> show parameter log_checkpoints_to_a

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------------------
log_checkpoints_to_alert             boolean     FALSE

可以觀察incremental checkpoint  記錄在alert.log中

SQL> alter system set log_checkpoints_to_alert=true;

系統已更改。

SQL> alter system set log_checkpoint_timeout=15;

系統已更改。

開啟alert.log

Incremental checkpoint up to RBA [0x19.37e.0], current log tail at RBA [0x19.79f.0]
Mon Nov 23 17:11:44 2009
Incremental checkpoint up to RBA [0x19.7ad.0], current log tail at RBA [0x19.7b1.0]
Mon Nov 23 17:12:06 2009
Incremental checkpoint up to RBA [0x19.7b4.0], current log tail at RBA [0x19.7b4.0]
Mon Nov 23 17:12:27 2009

第一個rba 是incremental checkpoint 發生時候的 檢查點位置lrba
第二個rba 是checkpoint發生時當前的on disk rba

 

完全檢查點與增量檢查點
完全檢查點(full checkpoint)
將寫出所有的dirty buffer,完全檢查點發生時候不能有新的dirty buffer 產生,知道full checkpoint完成
2種條件 觸發full checkpoint 1.非 abort shutdown database後,2.alter system checkpoint
full checkpoint會在datafile header,和controlfile中datafile部分 寫入當前SCN (RBA 也寫入)

SQL> select checkpoint_change# from v$datafile;

CHECKPOINT_CHANGE#
------------------
           1577210~~~~~~~~~~~~~~~~~~~資訊來自controlfile datafile部分(checkpoint scn)
           1577210
           1577210
           1577210

SQL> select checkpoint_change# from v$datafile_header;

CHECKPOINT_CHANGE#
------------------
           1577210
           1577210~~~~~~~~~~~~~~~~~~資訊來自datafile header部分(stat scn)
           1577210
           1577210


SQL> alter session set events 'immediate trace name file_hdrs level 10';

會話已更改。

SQL> alter session set events 'immediate trace name controlf level 8';

會話已更改。


trace dump  file_hdrs

DATA FILE #1:
  (name #7) G:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\SYSTEM01.DBF
creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1    (file_hdrs中 這部分資訊來自controlfile)
 tablespace 0, index=1 krfil=1 prev_file=0
 unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
 Checkpoint cnt:123 scn: 0x0000.001810fa 11/23/2009 17:16:44
 Stop scn: 0xffff.ffffffff 11/23/2009 17:16:26
 Creation Checkpointed at scn:  0x0000.00000009 08/30/2005 13:50:22 ******************這個就是full checkpoint發生時記錄的checkpoint scn

........................................................

FILE HEADER:
 Compatibility Vsn = 169869568=0xa200100
 Db ID=1230443873=0x49571561, Db Name='ORCL'                       (file_hdrs中 這部分資訊來自datafile)
 Activation ID=0=0x0
 Control Seq=850=0x352, File size=62720=0xf500
 File Number=1, Blksiz=8192, File Type=3 DATA
Tablespace #0 - SYSTEM  rel_fn:1
Creation   at   scn: 0x0000.00000009 08/30/2005 13:50:22
Backup taken at scn: 0x0000.00000000 01/01/1988 00:00:00 thread:0
 reset logs count:0x29e1c9e4 scn: 0x0000.0008297b reset logs terminal rcv data:0x0 scn: 0x0000.00000000
 prev reset logs count:0x21d66184 scn: 0x0000.00000001 prev reset logs terminal rcv data:0x0 scn: 0x0000.00000000
 recovered at 11/23/2009 17:16:43
 status:0x2004 root dba:0x00400179 chkpt cnt: 123 ctl cnt:122
begin-hot-backup file size: 0
Checkpointed at scn:  0x0000.001810fa 11/23/2009 17:16:44  ***************start scn
 thread:1 rba:(0x1a.2.10) *****************


SQL> select to_number('1810fa','xxxxxxxxx') from dual;

TO_NUMBER('1810FA','XXXXXXXXX')
-------------------------------
                        1577210


trace controlfile

可以看到controlflile中 記錄了 checkpointed at  scn的 資訊

 

***************************************************************************
DATA FILE RECORDS
***************************************************************************
 (size = 428, compat size = 428, section max = 100, section in-use = 4,
  last-recid= 18, old-recno = 0, last-recno = 0)
 (extent = 1, blkno = 11, numrecs = 100)
DATA FILE #1:
  (name #7) G:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\SYSTEM01.DBF
creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1
 tablespace 0, index=1 krfil=1 prev_file=0
 unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
 Checkpoint cnt:123 scn: 0x0000.001810fa 11/23/2009 17:16:44
 Stop scn: 0xffff.ffffffff 11/23/2009 17:16:26  *****************************stop scn

***************************************************************************
DATABASE ENTRY
***************************************************************************
 (size = 316, compat size = 316, section max = 1, section in-use = 1,
  last-recid= 0, old-recno = 0, last-recno = 0)
 (extent = 1, blkno = 1, numrecs = 1)
 11/11/2009 16:12:17
 DB Name "ORCL"
 Database flags = 0x00404000 0x00001000
 Controlfile Creation Timestamp  11/11/2009 16:12:18
 Incmplt recovery scn: 0x0000.00000000
 Resetlogs scn: 0x0000.0008297b Resetlogs Timestamp  11/11/2009 16:12:20
 Prior resetlogs scn: 0x0000.00000001 Prior resetlogs Timestamp  08/30/2005 13:49:56
 Redo Version: compatible=0xa200100

 Database checkpoint: Thread=1 scn: 0x0000.001810fa**************************checkpoint scn

 

***************************************************************************
REDO THREAD RECORDS
***************************************************************************
 (size = 256, compat size = 256, section max = 8, section in-use = 1,
  last-recid= 0, old-recno = 0, last-recno = 0)
 (extent = 1, blkno = 9, numrecs = 8)
THREAD #1 - status:0xf thread links forward:0 back:0
 #logs:3 first:1 last:3 current:1 last used seq#:0x1a
 enabled at scn: 0x0000.0008297b 11/11/2009 16:12:20
 disabled at scn: 0x0000.00000000 01/01/1988 00:00:00
 opened at 11/23/2009 17:16:44 by instance orcl
Checkpointed at scn:  0x0000.001810fa 11/23/2009 17:16:44 ************checkpoint scn

 


***************************************************************************
DATA FILE RECORDS
***************************************************************************
 (size = 428, compat size = 428, section max = 100, section in-use = 4,
  last-recid= 18, old-recno = 0, last-recno = 0)
 (extent = 1, blkno = 11, numrecs = 100)
DATA FILE #1:
  (name #7) G:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\SYSTEM01.DBF
creation size=0 block size=8192 status=0xe head=7 tail=7 dup=1
 tablespace 0, index=1 krfil=1 prev_file=0
 unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
 Checkpoint cnt:123 scn: 0x0000.001810fa 11/23/2009 17:16:44********************checkpoint scn

 


SQL> select to_number('1810fa','xxxxxxxxx') from dual;

TO_NUMBER('1810FA','XXXXXXXXX')
-------------------------------
                        1577210

 

oracle進行介質恢復的時候 就是對比controlfile中 datafile 的scn(也叫checkpoint scn) 與datafile header 的SCN(start scn)是否相等
不相等需要介質恢復

instance recover 是否進行,是比較start scn(datafile header),與controlfile中datafile資訊的 stop scn(v$datafile.last_change#)
stop scn正常執行時候 為 無窮大(Stop scn: 0xffff.ffffffff )只有資料庫 除abort shutdown後 觸發最後一次full checkpoint 則記錄這個full checkpoint的scn
啟動時候用datafile header 的start scn與 這個stop scn比較  檢查上次是否是正常關閉,如過database crash 則stop scn還是為無窮大,此時start scn =! stop scn
,oracle將進行instance recovery(crash recovery)

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

相關文章