ITPub博客

首页 > Linux操作系统 > Linux操作系统 > oracle实验记录(buffer_cache分析(4)dbwr,lgwr,ckpt)

oracle实验记录(buffer_cache分析(4)dbwr,lgwr,ckpt)

原创 Linux操作系统 作者:fufuh2o 时间:2009-12-10 16:55:45 0 删除 编辑

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(default 2)则选中该buffer header作为要替换掉的,返回该buffer header中记录的block在内存中的实际地址(然后找到内存中的block 清除掉)
输入 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 将当前buffer header tch的值 赋给_db_aging_stay_count 否则若_db_aging_stay_count>=_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 所以buffer header tch 4这个值 给_db_aging_stay_count(现在值为4了),oracle 继续搜索lru辅助list找到第2个buffer header tch为 4,按算法也不会重用,但此时_db_aging_stay_count>_db_aging_hot_criteria(4>2)此buffer header tch值减半变为(2),按此算法扫描lru辅助list上的块(这样轮询搜索时候 就会清除一批块出去)。

 

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

此时按逻辑算法查到buffer header 对应block 1 作为被替换的 (tch<_db_aging_hot_criteria)从buffer header中找到block 将其信息在内存中清除,(但此buffer header在 lru辅助list上位置不会变化,不会变成 首端),接着又发生2个select 分别需要block 5,block 4所以当前buffer header(最早对应block 1的,现在对应block 5)tch 为2,对应block 4的buffer header tch为2 并将2个 buffer header从lru 辅助list,放到lru主list中间位置, 此时lru辅助list上就挂着 对应block 2,block 3的buffer header tch均为1 ,此时又有seslet 需要用block 3 该block 对应的buffer header TCH加1=2放入LRU主list中间位置 (此时主lru list 按块对应的buffer headr在list的位置 应该为 尾 5(原block1的buffer header) 中间 3 首端 4),又一条sql需要block 2 该block 对应的buffer header tch+1=2放入lru主list中间(lru辅助list不挂buffer header了)
,若又有新的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博客 ” ,链接:https://blog.itpub.net/12020513/viewspace-622152/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2009-06-26

  • 博文量
    182
  • 访问量
    471638