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/ ,如需转载,请注明出处,否则将追究法律责任。