Skip to content

All posts by Guang Cai Li - 4. page

1.working set与Latch:cache buffers lru chain:
每个working set都具有它自己的一组LRU和LRUW链表(LRU和LRUW链表总是成对出现的)。
ORACLE为了提高buffer cache性能(大内存),使用了多个working set
每个working set都由一个名为“Latch:cache buffers lru chain”的latch来保护,每一个lru latch对应一个working set。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set(包含的LRU链表)上去–。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。也就是说,当buffer cache加载一个新的数据块时,其对应的buffer header会去找一个可用的lru latch,如果没有找到,则再找下一个lru latch,直到找到为止。如果轮询完所有的lru latch也没能找到可用的lru latch,该进程只有等待latch free等待事件,同时出现在v$session_wait中,并增加“latch misses”。
如果启用了多个DBWR后台进程的话,每个DBWR进程都会对应一个不同的working set,而且每个DBWR只会处理分配给它的working set,不会处理其他的working set。

2.cache buffers lru chain LATCH的个数:
ORACLE默认创建的cache buffers lru chain LATCH数量与CPU个数、DBWR个数相关。
DBWR小于4,个数为:4*CPU个数
DBWR大于4,个数为:DBWR*CPU个数
每个buffer pool使用自己的cache buffers lru chain LATCH,一个数据库实例可以配置:DEFAULT,2KB,4KB,8KB,16KB,32KB,KEEP,RECYCLE 这8种类型的buffer pool,故cache buffers lru chain LATCH的数量最少为8个。详见: 点击打开链接
或使用以下语句查出buffer cache中各个pool中cache buffers lru chain LATCH的获取情况: –语句来自周亮《ORACLE DBA实战攻略》
SYS@ bys3>select d.blk_size,c.child#,p.bp_name,c.gets,c.sleeps from x$kcbwds d,v$latch_children c,x$kcbwbpd p where d.set_latch=c.addr and d.set_id between p.bp_lo_sid and p.bp_hi_sid order by c.child#;

BLK_SIZE CHILD# BP_NAME GETS SLEEPS
———- ———- ——————– ———- ———-
8192 1 KEEP 18 0
8192 3 RECYCLE 18 0
8192 5 DEFAULT 864096 144
2048 7 DEFAULT 18 0
4096 9 DEFAULT 18 0
8192 11 DEFAULT 18 0
16384 13 DEFAULT 18 0
32768 15 DEFAULT 18 0

在我的虚拟机中,CPU是一个,在10G中是有8个LRU LATCH,在11GR2中,是16个LRU LATCH.见:http://blog.csdn.net/haibusuanyun/article/details/19084583#t6

3.cache buffers lru chain LATCH在什么情况下需要使用:
数据块读入buffer cache前需要获得cache buffers lru chain LATCH–因为要到LRU上找空闲buffer
DBWR扫描LRUW链表前需要获得cache buffers lru chain LATCH
SMON将空闲buffer移动至LRU辅助列,也需要cache buffers lru chain LATCH。
4.cache buffers lru chain LATCH在哪些情况下出现争用:
简单说就是多个进程同时检索LRU/LRUW时出现。
具体情况有: –物理读过多引起争用概念高。
多个会话并发访问不同表或索引,因为这样发生物理读可能较大–由上面可知物理读时需要在LRU找空闲buffer
脏块过多,DBWR写出慢(DBWR的性能不足-主机性能问题,或者磁盘I/O),涉及DBWR调优-在此不多讨论。

注:CBC LATCH主要发生在逻辑读时-多会话并发访问相同的表或索引-相同表或索引多集中于几条相同hash chain。

buffer cache实验6-latch:cache buffers lru chains

1.CBC latch产生的原理:
一次逻辑读时CBC latch锁及Buffer pin锁的获取和释放过程如下:
1.加Latch X
2.进入hash chain,在相应的BH上加Buffer pin S (0–>1)
3.释放Latch X
4.进行逻辑读–也就是通过BH中的buffer adderss找到数据块在内存中真实位置 —假如读了1MS
5.加Latch X
6.释放Buffer pin S (1–>0) 0:没锁 1:共享锁 2:独占锁
7.释放Latch X
物理读时需要将数据块的buffer header挂载到hash chain上,也需要获取CBC LATCH,buffer header中有hash chain的信息,BH挂载到hash chain上,应该在BH内存结构中会有信息更改,BH的修改也就需要有Buffer pin了,锁的获取和释放应该和逻辑读时差不多,不过是在Buffer pin S 上要加2号独占锁。当然这一点是我大胆推测的哈哈。

CBC latch上一般都用的独占锁,使用共享锁的情况是:9I后在索引的根、枝叶读时使用共享CBC LATCH,无BUFFER PIN方式访问上
BH上Buffer pin锁状态:
0 未加锁
1 共享锁,读BUFFER BLOCK —SELECT
2 独占锁,写BUFFER BLOCK —DML语句

2.从CBC latch产生的原理可以发现,出现CBC LATCH争用会有以下情况:

1.CBC latch保护不同的链表、不同BH :同一CBC LATCH下多个hash chain上的多个BH被同时访问时,
2.CBC latch保护同一链表下同一BH :同一hash chain上同一BH被同时访问时
3.物理读将数据块挂载到hash chain上时,多个物理块HASH冲突都挂载到同一个hash chain或者要挂载的hash chain上的BH在被逻辑读
这里的被访问,可能发生在逻辑读或者物理读,即:使用到CBC latch的场景是:
服务器进程需要扫描hash chain上数据块–逻辑读
服务器进程需要将数据块挂载到hash chain上–物理读
关于hash chain与hash bucket,详见本系列第一篇: 点击打开链接

3.关于CBC LATCH争用的模拟实验,有两种思路:
一是热链–这个不太好模拟,我也没做成功。
二是热块-这个好模拟,同时还会有buffer busy waits,具体实验见: 点击打开链接

4.latch: cache buffers chains 解决思路:
1、热链:调整_db_block_hash_latches加大latch数量,作用是减少同一LATCH下多个桶被同时访问的情况。即多个表的相应块在BUFFER CACHE中对应不同BH,不同BH又对应在不同HASH BUCKETS,但是这多个HASH BUCKETS是属于同一个LATCH。。
alter system set “_db_block_hash_latches”=10240 scope=spfile;
2、热块:调整BUFFER _CACHE,参数:db_cache_size,big integer 100M
热块是:同一表在BUFFER CACHE中的块(一个块对应一个BH,BH对应一个HASH BUCKET)被多个会话同时读,–全表扫描时容易出现。可以使用多个会话同时读取同一表的同一行的方式来模拟产生CBC latch,查询时使用ROWID做条件,查询速度快,更容易引起CBC latch。
3、修改应用,减少全表扫描,也就是优化SQL语句了

例如:CBC Latch的产生次数的查询:
SYS@ bys3>col name for a20
SYS@ bys3>select NAME,GETS ,MISSES ,SLEEPS ,IMMEDIATE_GETS, IMMEDIATE_MISSES from v$latch where name like ‘%cache buffers chains%’;
NAME GETS MISSES SLEEPS IMMEDIATE_GETS IMMEDIATE_MISSES
——————– ———- ———- ———- ————– —————-
cache buffers chains 2006932 0 0 78095 0

buffer cache实验5-latch:cache buffers chain

1.检查点概念–chkpoint
检查点是一个数据库事件,存在的意义在于减少崩溃恢复crash recovery时间.
检查点事件由后台进程CKPT触发,当检查点发生时,CKPT通知DBWR进程将脏数据库dirtybuffer写出到数据文件上,更新数据文件头及控制文件上的检查点信息。
数据文件头的SCN是CHECKPOINT SCN.

检查点工作原理:
在数据库中,进行数据修改时,需要先将数据读和内存中buffer cache,修改数据同时,ORACLE会记录重做redo信息用于恢复,有了重做日志信息存在,ORACLE不需要在事务提交时commit立刻将变化的数据写回磁盘,因为立刻写效率会低。重做信息存在也为数据崩溃后,数据可以恢复。如断电,内存中修改过未写入数据文件的数据丢失,下一次数据库启动时,可以通过重做日志进行事务重演(不管是否提交),即前滚。将数据库恢复至崩溃前状态,然后数据库可以打开提供使用,之后ORACLE将未提交的事务回滚。
检查点存在是为了缩短上述数据恢复的时间。
当检查点发生时,此时的SCN称为checkpoint scn,ORACLE会通知DBWR,把修改过的数据,即此checkpoint scn之前的脏数据dirty data从buffer cache写入磁盘,写入完成后,CKPT进程会相应更新控制文件和数据文件头,记录此检查点信息,标识变更。
检查点完成后,此检查点之前修改过后 数据都已经写出到数据文件,重做日志中的相应重做记录对于实例恢复已经无用(物理恢复有用)。
######################################################################
2.增量检查点概念 incremental checkpoint 及CKPTQ,FILEQ
检查点队列,checkpoint queue,CKPTQ;
在数据库内部,每个脏数据块会被记录到检查点队列,按LRBA(LOW RBA 第一次修改数据块对应的redo block address,后面修改的RBA称为HRBA)顺序排列,如果一个数据块多次修改,该数据块在检查点队列上顺序不变化。
非脏块的buffer header中的CKPTQ信息为空。
执行增量检查点时,DBWR从检查点队列按照LOW RBA顺序写出,先修改的数据可以被按优先顺序写出,实例检查点因此可以不被增进。
同时CKPT进程阶段性使用轻量级控制文件更新协议将当前最低RBA写入控制文件,CKPT在进行轻量级更新时,不改写控制文件中数据文件中检查点信息以及数据文件头信息,只记录控制文件检查点SCN,controlfile checkpointed at scn 并根据增量检查点写出增进RBA信息。
通过增量检查点,数据库可以将全部写出改为增量渐进写出,从而极大减少对于数据库性能的影响, 而检查点队列进一步将RBA和检查点关联起来,从而可以通过检查点确定恢复的起点。
与CKPTQ相关的是:文件检查点队列 file queue FILEQ与对象队列Obj-Q
文件检查点提高了表空间检查点TABLESPACE CHECKPOINT的性能,每个dirty buffer同时链接到CKPTQ和FILEQ,CKPTQ包含实例所有需要执行检查点的BUFFER,FILEQ包含属于特定文件需要执行检查点的BUFFER,每个文件都包含一个文件队列,在执行表空间检查点请求时使用FILEQ。–表空间OFFLINE会触发表空间检查点。

3.CKPT进程在增量检查点中的作用:
CKPT进程监控着检查点队列的长度,当检查点队列长度达到一定限制时,CKPT会通知DBWR写脏块
CKPT会根据参数的设置和I/O的速度以及繁忙程度,计算出来一个Target rba(目标rba),DBWR会沿着检查点队列,将所有Target rba之前的脏块刷新到磁盘.当CKPT通知完DBWR Target rba后,CKPT的任务就结束了.并不会等待DBWR写完所有的Target rba之前的脏块.

通知DBWR写脏块,这是CKPT的任务之一,CKPT另一个任务,就是每3秒,检测一次DBWR的写进度.
检查点队列最前面的块被称为检查点位置.DBWR是沿着检查点队列写脏块的,CKPT每3秒钟查看一下DBWR沿检查点队列写到了哪里,并且将这个位置设置为检查点位置.也就是说检查点位置之前的块,都是已被DBWR刷新到磁盘上的块.
这个3秒一次检查DBWR进度的工作,也是CKPT的一个重要的任务.CKPT每3秒一次将检查点位置记录进控制文件,当然同时被记录进控制文件的还有’心跳’等其他信息.

CKPT每3秒一次的工作和CKPT定期触发DBWR,这两项操作合一起被称为–增量检查点.

4.dbwr 写CKPTQ上脏块的方式:
在检查点队列中,脏块根据按LRBA顺序排列,DBWR每到一定的时机,被触发。
硬件能力、脏块数、Redo数三个指标,是DBWR是否写脏块的依据。
DBWR什么时候(多久)判断一次这三个值标: 3s
也就是:DBWR 3秒醒来,依据三个指标判断是否触发—— “增量检查点写”

5.fast_start_mttr_target与增量检查点
一、关于FAST_START_MTTR_TARGET概念: –此段百度哈哈
是一个加快实例恢复的参数,我们可以根据服务级别来定义一个合理的、可接受的值,该值的单位为秒。比如设定为60s,即2分钟。
假定该值处于合理的情况之下,则一旦实例崩溃,在60s以内实例应当能够被恢复。合理即是该值不能太大,也不能太小。太大则实例恢复所需的时间较长,太小则导致大量数据的及时写入,增加了系统的I/O。
影响实例恢复时间长短的主要因素即是从最近检查点位置到联机重做日志尾部之间的距离。距离越长则所需要的cache recovery 和undo、redo的时间越长。所以如何有效的缩短最近检查点位置与联机重做日志尾部之间的距离,这正是FAST_START_MTTR_TARGET的目的。

关于检查点的触发条件有很多,比如日志切换、数据库shutdown、开始结束备份表空间等。检查点的分类也很多,比如完全检查点、部分检查点、增量检查点等。
FAST_START_MTTR_TARGET的值实际上也是触发检查点的一个触发条件。当内存中产生的dirty buffer所需的恢复时间(estimated_mttr)如果到达FAST_START_MTTR_TARGET的指定时间,则检查点进程被触发。检查点进程一旦被触发,将通知DBWn进程将按检查点队列顺序将脏数据写入到数据文件,从而缩短了最后检查点位置与联机重做日志间的距离,减少了实例恢复所需的时间。

二、FAST_START_MTTR_TARGET参数的设置
9i之后(包括9i):fast_start_mttr_target:以实例恢复时间为单位(硬件能力、脏块数、Redo数)
10G之后,fast_start_mttr_target默认值为0,即开启自调节检查点:self tune checkpoint ,自调节检查点的受影响因素有:硬件能力、脏块数、Redo数
自调节检查点对应隐含参数:_disable_selftune_checkpointing:
_disable_selftune_checkpointing Disable self-tune checkpointing FALSE
SYS@ bys3>show parameter statistics_level –此参数为typical 或者all,再加上FAST_START_MTTR_TARGET 设置为非零值就启用MTTR Advisory

NAME TYPE VALUE
———————————— ———– ——————————
statistics_level string TYPICAL
SYS@ bys3>show parameter mttr
NAME TYPE VALUE
———————————— ———– ——————————
fast_start_mttr_target integer 0
从alert日志中数据库启动时的信息可以发现:
[oracle@bys3 ~]$ cat alert_bys3.log |grep MTTR
MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set

显式的设置alter system set FAST_START_MTTR_TARGET=0会关闭自动调节,重启数据库在alter日志中可以发现:
MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set

当FAST_START_MTTR_TARGET显示设为非零
SYS@ bys3>alter system set fast_start_mttr_target=25;
即: statistics_level参数为typical 或者all,再加上FAST_START_MTTR_TARGET 设置为非零值就启用MTTR Advisory
此时alert日志中不会有MTTR信息–因为已经正常启动MTTR Advisory

三、关于启动MTTR Advisory时v$instance_recovery;视图的使用: –未开启MTTR Advisory时此视图内容为空。
SYS@ bys3>select mttr_target_for_estimate ,dirty_limit,estd_cache_writes ,estd_cache_write_factor ,estd_total_writes ,estd_total_write_factor from v$mttr_target_advice;
MTTR_TARGET_FOR_ESTIMATE DIRTY_LIMIT ESTD_CACHE_WRITES ESTD_CACHE_WRITE_FACTOR ESTD_TOTAL_WRITES ESTD_TOTAL_WRITE_FACTOR
———————— ———– —————– ———————– —————– ———————–
18 1067 57 1 806 1
17 1000 57 1 806 1
19 1268 57 1 806 1
20 1507 57 1 806 1
SYS@ bys3>select target_mttr,estimated_mttr from v$instance_recovery;
TARGET_MTTR ESTIMATED_MTTR
———– ————–
20 12
–mttr_target_for_estimate有一个值为的最接近设定的目标时间20,以及由系统计算出的的target_mttr时间20
–同时也给出了几组不同的mttr_target值及dirty_limit,cache_write,io 等来供选择,设定合适的mttr值

buffer cache实验4-ckptq的工作机制与增量检查点及fast_start_mttr_target参数

Buffer Header结构图及简介
图1:


buffer header:每一个数据块在被读入buffer cache时,都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应。buffer header包含的主要信息有:
1) 该数据块在buffer cache中实际的内存地址。就是上图中的虚线箭头所表示的意思。
2) 该数据块的类型,包括data、segment header、undo header、undo block等等。
3) 该buffer header所在的hash chain,是通过在buffer header里保存指向前一个buffer header的指针和指向后一个buffer header的指针的方式实现的。
4) 该buffer header所在的LRU、LRUW、CKPTQ等链表(这些链表我们后面都会详细说明)。也是通过记录前后buffer header指针的方式实现。
5) 当前该buffer header所对应的数据块的状态以及标记。
6) 该buffer header被访问(touch)的次数。
7) 正在等待该buffer header的进程列表(waiter list)和正在使用该buffer header的进程列表(user list)。
DUMP 指定的BUFFER BLOCK–含BH方法如下: –数据库版本:11.2.0.4
–补充下,如果是要DUMP整个BUFFER CACHE,可以参考:http://blog.csdn.net/haibusuanyun/article/details/17439845

BYS@ bys3>select dept.*,dbms_rowid.rowid_object(rowid) object#,dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,dbms_rowid.rowid_row_number(rowid) row# from dept;
DEPTNO DNAME LOC OBJECT# FILE# BLOCK# ROW#
———- ————– ————- ———- ———- ———- ———-
10 ACCOUNTING NEW YORK 22327 4 251 0
20 RESEARCH DALLAS 22327 4 251 1
40 OPERATIONS BOSTON 22327 4 251 2
99 chedan bj 22327 4 251 3
BYS@ bys3>select dbms_utility.make_data_block_address(4,251) from dual;
DBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(4,251)
——————————————-
16777467

alter session set events ‘immediate trace name set_tsn_p1 level 5’;
alter session set events ‘immediate trace name buffer level 16777467’;
select value from v$diag_info where name like ‘De%’;

select * from x$bh where DBARFIL=4 and DBABLK=251; 用SYS用户从X$BH查看相应信息对照DUMP文件查看。
#########################################################
解读Buffer Header –结合X$BH
说明:DUMP BUFFER中一个块方法就是上一步的,可以先从多个会话对此块进行查询或DML之类,然后DUMP此块。下面的两段BH的内容是不是从同一个DUMP生成的文件中截取的已经记不清了。这里只是介绍了DUMP文件的BH中各个字段的意义,对已经知道的BH中各个字段与X$BH,V$BH中字段的对应也有写上。关于X$BH中字段,可以参考: X$BH中各字段意义
而对于像:什么情况下 lru-flags: hot_buffer或lru-flags: moved_to_tail,什么情况下st: CR或 st: XCURRENT,暂不在本文讨论范围了!
后面尽量按照DUMP的BH中一句一句的顺序进行解读,但是因为ru-flags: flags: obj-flags:这种并不在每一次DUMP中出现,所以这一块内容汇总在一起了–注意我下面的ru-flags: flags: obj-flags:等在下面贴出来的两个BH中可能没出现,是从其它DUMP文件中贴过来的。
最后,这方面参考资料较少,难免有疏漏之处,欢迎补充、指错!!
######
Dump of buffer cache at level 10 for tsn=4 rdba=16777467
1. BH (0x213e6ad0) file#: 4 rdba: 0x010000fb (4/251) class: 1 ba: 0x210b0000
2. set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 0,0
3. dbwrid: 0 obj: 22327 objn: 22327 tsn: 4 afn: 4 hint: f
4. hash: [0x2bbfddf4,0x213e7680] lru: [0x213e76b0,0x22ff07ec]
5. lru-flags: moved_to_tail
6. ckptq: [NULL] fileq: [NULL] objq: [NULL] objaq: [NULL]
7. st: CR md: NULL fpin: ‘kdswh11: kdst_fetch’ tch: 1
8. cr: [scn: 0x0.3a9dcc],[xid: 0x0.0.0],[uba: 0x0.0.0],[cls: 0x0.3a9dcc],[sfl: 0x0],[lc: 0x0.359e7e]
9. flags: only_sequential_access
10. buffer tsn: 4 rdba: 0x010000fb (4/251)
11. scn: 0x0000.00359e7e seq: 0x01 flg: 0x04 tail: 0x9e7e0601
12. frmt: 0x02 chkval: 0x8cd6 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
第二个
BH (0x21fe5dec) file#: 4 rdba: 0x010000fb (4/251) class: 1 ba: 0x21c92000
set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 0,0
dbwrid: 0 obj: 22327 objn: 22327 tsn: 4 afn: 4 hint: f
hash: [0x213e7680,0x233f2418] lru: [0x233f76c8,0x233f2448]
ckptq: [NULL] fileq: [NULL] objq: [0x233f76e0,0x240796ec] objaq: [0x233f76e8,0x240796e4]
use: [NULL] wait: [NULL]
st: XCURRENT md: NULL fpin: ‘kdswh11: kdst_fetch’ tch: 2 txn: 0x293d0380
flags: private
LRBA: [0x0.0.0] LSCN: [0x0.3a9dcd] HSCN: [0x0.3a9dcd] HSUB: [65535]
buffer tsn: 4 rdba: 0x010000fb (4/251)
scn: 0x0000.00359e7e seq: 0x01 flg: 0x04 tail: 0x9e7e0601
frmt: 0x02 chkval: 0x8cd6 type: 0x06=trans data
Hex dump of corrupt header 3 = CHKVAL
Dump of memory from 0x21C92000 to 0x21C92014
#############################################
解读Buffer Header,也是对X$BH中相应字段的更详解读
第一句:
BH (0x213e6ad0) file#: 4 rdba: 0x010000fb (4/251) class: 1 ba: 0x210b0000
BH (0x213e6ad0) ,这是BH的HASH值
file#: 4 ,对应X$BH.FILE#,此块在4号文件里,通过v$dbfile.FILE#可以查出来对应的数据文件
rdba: 0x010000fb (4/251),rdba就是rowid中的相对文件号rfile#+block#块号。通过DBMS_ROWID查出块的rfile#+block#,使用select dbms_utility.make_data_block_address(4,251) from dual;这种方法可以计算出来十进制的rdba。这里的10000fb用to_number函数转换为10进制就是前面计算出来的:16777467。。0x010000fb转成二进制时,由相对文件号10位 block号22位。
class: 1,对应X$BH.class –表示buffer header对应block的类型,1=data block。详见本段Buffer Header解析最后。
ba: 0x210b0000 对应X$BH.BA,这是BUFFER中block address,是块在内存中的物理地址。
第二句:
set: 3 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 0,0
set: 3:对应X$BH.STATE,CR(3)=作为一致性读镜像的数据块,详见本段Buffer Header解析最后。
bsz: 8192,块大小8192KB。这个可以在 dba_tablespaces.BLOCK_SIZE 查询出数据文件的块大小。
第三句:
dbwrid: 0 obj: 22327 objn: 22327 tsn: 4 afn: 4 hint: f
obj: 22327,对应X$BH.OBJ ,也就是块上数据在哪个对象里– dba_objects.DATA_OBJECT_ID,这个查询渠道很多。
第四句:
hash: [0x2bbfddf4,0x213e7680] lru: [0x213e76b0,0x22ff07ec]
hash: [0x2bbfddf4,0x213e7680] 一一对应x$bh.nxt_hash x$bh.prv_hash这里用链表,指出下一个及前一个BH的HASH值。如果这个hash chain上只有一个bh,则这里的前一个及后一个BH的hash值都是此BH。
lru: [0x213e76b0,0x22ff07ec] 一一对应x$bh.nxt_repl x$bh.prv_repl这里用链表,指出下一个及前一个BH的在LRU链上HASH值。
第五句:
lru-flags: moved_to_tail 对应x$bh. LRU_FLAG 表示该数据块经历了依次全表扫描,它被移到LRU的冷端,随时都可能被age out。
lru-flags为0时,在DUMP BUFFER时可能不显示lru-flags: 这一行。
lru-flags: on_auxiliary_list
可能出现的:
obj-flags: object_ckpt_list 对应 x$bh.OBJ_FLAG,,文件队列的对应对应 x$bh.RFLAG
flags: only_sequential_access 对应x$bh. FLAG
flags: buffer_dirty block_written_once redo_since_read –在DML后可能会出现这种状态的 flags
flags: buffer_dirty redo_since_read
第六句:
ckptq: [NULL] fileq: [NULL] objq: [0x22ff8054,0x24839390] objaq: [0x22ff805c,0x24839388]
ckptq: [NULL] 在检查点队列上的HASH值,这里为空
fileq: [NULL] 在文件队列上的HASH值
objq: [0x22ff8054,0x24839390] 对应x$bh.oq_nxt x$bh.oq_prv .对象队列HASH值
objaq: [0x22ff805c,0x24839388] 对应x$bh.aq_nxt x$bh.aq_prv.辅助对象队列HASH值

第七句
st: CR md: NULL fpin: ‘kdswh11: kdst_fetch’ tch: 1
st: CR :对应x$bh.state CR, a consistent read (stale) block image 一致读。 详见本段Buffer Header解析最后。
tch: 1 对应X$BH.TCH,Touch的缩写,表示一个Buffer的访问次数–不过不是绝对,3秒内访问同一块,TCH不增加。与此相关的一个字段是: X$BH.tim –Touch Time

第八句
cr: [scn: 0x0.3a9dcc],[xid: 0x0.0.0],[uba: 0x0.0.0],[cls: 0x0.3a9dcc],[sfl: 0x0],[lc: 0x0.359e7e]
[scn: 0x0.3a9dcc] 产生此CR块时的SCN

第九句:
buffer tsn: 4 rdba: 0x010000fb (4/251)
这个块的TSN 表空间号和RDBA
第十句:
scn: 0x0000.00359e7e seq: 0x01 flg: 0x04 tail: 0x9e7e0601
scn: 0x0000.00359e7e,SCN直接转换为用to_number函数转换为10进制就是数据库内查出的SCN了,是这个块的状态改变时的SCN。详见:http://blog.csdn.net/haibusuanyun/article/details/17029517
seq: 0x01
flg: 0x04 flg:0x01 (新建块)0x2(数据块延迟清洗推进scn和seq) 0X04(设置校验和) 0x08(临时块) 0x00普通块
第十一句:
frmt: 0x02 chkval: 0x8cd6 type: 0x06=trans data
type:0x06(表/索引块)
frmt: 0x01(v7) 0x02(v8)
##############################
第二个块BH与不同的有:
LRBA: [0xe3.e8e5.0] LSCN: [0x0.3a9dcd] HSCN: [0x0.3a9dcd] HSUB: [65535]
LSCN: [0x0.3a9dcd] HSCN: [0x0.3a9dcd] 修改时的SCN–如记录有修改时的SCN,可以转换此十六进制为SCN进行对比
LRBA: [0xe3.e8e5.0] 应该是最低REDO BYTE ADDRES,[0xe3.e8e5.0]对应 日志号,块号,第几字节起。也可能会有HRBA ,recovery rba 。
use: [NULL] wait: [NULL] 对应BH中的 users list ; waiters list
################################################################
附:
flag中,每位代表如下含义:

bit bit
0 buffer_dirty 14 stale
1 notify_after_change 15 deferred_ping
2 mod_started 16 direct_access
3 block_has_been_logged 17 hash_chain_dump
4 temp_data 18 ignore_redo
5 being_written 19 only_sequential_access
6 waiting_for_write 20 prefetched_block
7 multiple_waiters 21 block_written_once
8 recovery_reading 22 logically_flushed
9 unlink_from_lock 23 resilvered_already
10 down_grade_lock 25 redo_since_read
11 clone_being_written 29 plugged_from_foreign_db
12 reading_as_CR 30 flush_after_writing
13 gotten_in_current_mode
class:表示buffer header对应block的类型:
1=data block, 9=2nd level bmb,
2=sort block, 10=3rd level bmb,
3=save undo block, 11=bitmap block,
4=segment header, 12=bitmap index block,
5=save undo header, 13=unused,
6=free list, 14=undo header,
7=extent map, 15=undo block
state:
0, FREE, no valid block image
1, XCUR, a current mode block, exclusive to this instance 正在被当前的instance独占。
2, SCUR, a current mode block, shared with other instances正在被当前的instance共享
3, CR, a consistent read (stale) block image 一致读
4, READ, buffer is reserved for a block being read from disk 正在从磁盘上读取块
5, MREC, a block in media recovery mode 处于介质恢复模式
6, IREC, a block in instance (crash) recovery mode处于实例恢复模式

0,’free’,1,’xcur’,2,’scur’,
3,’cr’, 4,’read’,5,’mrec’,
6,’irec’,7,’write’,8,’pi’, 9,’memory’
10,’mwrite’,11,’donated’, 12,’protected’,
13,’securefile’, 14,’siop’,15,’recckpt’,
16, ‘flashfree’, 17, ‘flashcur’, 18, ‘flashna’

lru_flag

SYS@ bys3>select distinct(lru_flag) from x$bh;

LRU_FLAG
———-
6
4
8
0

select lru_flag,tch,BA,decode(state,0,’free’,1,’xcur’,2,’scur’,3,’cr’, 4,’read’,5,’mrec’,6,’irec’,7,’write’,8,’pi’, 9,’memory’,10,’mwrite’,11,’donated’, 12,’protected’, 13,’securefile’, 14,’siop’,15,’recckpt’, 16, ‘flashfree’, 17, ‘flashcur’, 18, ‘flashna’) status from x$bh where FILE#=4 and DBABLK=251;

select file#,block#,status from v$bh where objd=(select data_object_id from dba_objects where owner=’bys’ and object_name=’TEST’) and block#=341892 order by block#;

buffer cache实验2-详解Buffer Header–DUMP buffer结合X$BH视图各字段

1.为什么要使用buffer cache???
buffer cache就是一块含有许多数据块的内存区域,这些数据块主要都是数据文件里的数据块内容的拷贝。
从buffer cache中读取一个数据块一般需要100ns左右,从一般的存储硬盘中读取一个数据块需要10ms;所以大概算一下,从内存中读取数据块比从硬盘中快近十万倍。
故oracle在读取数据块时,先在buffer cache中查找,如存在,则读取–逻辑读;如果数据块不存在,则发生物理读,从物理文件中将数据读入buffer cache(不考虑直接读的情况)。
在初始化参数中,设置buffer cache大小的参数是db_cache_size
在11.2.0.4.0中此参数支持动态修改:
BYS@ bys3>show parameter db_cache_size
NAME TYPE VALUE
———————————— ———– ——————————
db_cache_size big integer 48M
BYS@ bys3>alter system set db_cache_size=40M;
System altered.
BYS@ bys3>show parameter db_cache_size
NAME TYPE VALUE
———————————— ———– ——————————
db_cache_size big integer 40M

buffer cache所提供的功能主要包括:
1) 通过缓存数据块,从而减少I/O。
2) 通过构造CR块,从而提供读一致性功能。
3) 通过提供各种lock、latch机制,从而提供多个进程并发访问同一个数据块的功能。

2.buffer cache的内存结构图解
话说大神们都用WORD画图,为了模仿大神, 我也用WORD画了好久的原创:

从这张buffer cache的内存结构图,用一句话来说明
buffer cache中 结构大致是:buffer pool—>working set—>CBC latch—>hash bucket—>hash chain—>buffer header—>buffer dba
下面就把这些结构的概念大致说明一下: –更详细的的在之后

1.buffer header:
每一个数据块在被读入buffer cache时,都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应(buffer header 中有指定buffer 具体内存地址的信息)。

buffer header包含的主要信息有: 详见:
1) 该数据块在buffer cache中实际的内存地址。
2) 该数据块的类型,包括data、segment header、undo header、undo block等等。
3) 该buffer header所在的hash chain,是通过在buffer header里保存指向前一个buffer header的指针和指向后一个buffer header的指针的方式实现的。
4) 该buffer header所在的LRU、LRUW、CKPTQ等链表(这些链表我们后面都会详细说明)。也是通过记录前后buffer header指针的方式实现。
5) 当前该buffer header所对应的数据块的状态以及标记。
6) 该buffer header被访问(touch)的次数。
7) 正在等待该buffer header的进程列表(waiter list)和正在使用该buffer header的进程列表(user list)。

我的测试环境:buffer cache大小是40M,buffer的个数是4936(每个buffer在x$bh中都存在一条记录)。 在11G中db_cache_size 是一个动态参数,可以手动更改此参数后再查询x$bh,可以发现buffer的个数也会随之变化的。
SYS@ bys3>show parameter db_cache_si 如果是动态SGA管理,应该查:select * from v$sga_dynamic_components;
NAME TYPE VALUE
———————————— ———– ——————————
db_cache_size big integer 40M
SYS@ bys3>select count(*) from x$bh; –用这句查出buffer的个数,也就是可以存放4936个数据块(因为还有一部分空间是生成buffer header),db_cache_size/4936-8K就能算出一个buffer header的大致大小
COUNT(*)
———-
4936

BH buffer header—-block_buffers块个数是一一对应的,事实上相等
BH的大小计算– 即db_cache_size的大小减去block_buffers*8K –这里数据库的默认块大小是8K

10G中BH的大小:9I据说是 188byte.
SYS@ ocm1>select 48*1024*1024/5988-8192 from dual;
48*1024*1024/5988-8192
———————-
213.418838

在数据库中知道 FILE# BLOCK#如何查询ba buffer address
SYS@ bys3> select ba from x$bh where dbarfil=4 and dbablk=171; –32位LINUX,需要用SYS用户查X$BH
BA
——–
207A4000 —内存中的位置,16进制,一个16进制表示4bit,对应32位OS
################################
2.hash chain与hash bucket:
从上图中可以看到,一个hash bucket是对应着一条hash chain的。Hash Bucket-直译叫hash桶
Hash Bucket 一个逻辑上的概念,通过对buffer header 里记录的数据块地址和数据块类型运用hash算法以后,得到的组号。
hash chain 将属于同一个hash bucket的所有buffer header串起来的链表

服务器进程将数据块读取到buffer cache后,将数据块的DBA进行HASH运算,将具有相同HASH值的数据块的buffer header挂载到同一个hash bucket下(可能多个块的HASH值相同),并用hash chain串联起来。
buffer cache中,缺省的hash bucket的数量或者说缺省有多少条hash chain链表,是由一个隐藏参数: _db_block_hash_buckets决定的。
关于_db_block_hash_buckets参数的取值:据说在8i下,该参数缺省为db_block_buffers×2;但是到了9i以后,该参数似乎取的是小于且最接近于db_block_buffers×2的素数。
在ORACLE 10G和11G中,默认值是大于2倍的buffer数量的最小的2的幂的值。举例如buffer数量是500,2倍就是1000,那么大于1000的最小的2的幂的值是1024,也就是就会有1024个hash bucket。

在我测试系统中:buffer 数量是4936,2倍是9872,从隐含参数_db_block_hash_buckets 查出bufket数量是16384 ,完全符合。
SYS@ bys3>select count(*) from x$bh; –用这句查出buffer的个数
COUNT(*)
———-
4936
P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
—————————————- ————————————————– —————————— ——— ———- —–
_db_block_hash_buckets Number of database block hash buckets 16384 TRUE FALSE FALSE
_db_block_hash_latches Number of database block hash latches 1024 TRUE FALSE FALSE
SYS@ bys3>show parameter db_block_size
NAME TYPE VALUE
———————————— ———– ——————————
db_block_size integer 8192

而一条hash chain上的buffer header数量,没有固定限制(CR块有限制,一条hash chain上的CR块不能超过6个)。从隐含参数 _db_block_max_cr_dba中可以查到这个限制:
P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
—————————————- ————————————————– —————————— ——— ———- —–
_db_block_max_cr_dba Maximum Allowed Number of CR buffers per dba 6 TRUE FALSE FALSE

判断是否有过长的hash chain的语句:过长的hash chain更容易引起热链进而引起CBC LATCH
SYS@ bys3>select * from (select hladdr,count(*) from x$bh group by hladdr order by 2 desc) where rownum<5; –x$bh.hladdr表示的是hash chain latch address
HLADDR COUNT(*)
——– ———-
2A3A46CC 14
2A7F0864 14
2A3A4EAC 13
2A7F26EC 12
在热链问题发生时,可以通过两种方法来增加hash chain数量:1、调整隐含参数_db_block_hash_buckets –有风险 2.按ORACLE 10G和11G中,bucket数量的默认值是大于2倍的buffer数量的最小的2的幂的值的公式,来计算出让系统自动调整bucket数量时buffer cache需要增加到的大小。–查出现在的_db_block_hash_buckets 数量,除以2,将得出值乘以当前数据块大小(暂不考虑bh大小,也可以把一个bh大小按1K或512bytes来计算),就可以得出要调整到的buffer cache大小。– 注意注意:这个调整重启后才生效。
按我测试环境中值来计算:_db_block_hash_buckets 16384 ,db_block_size 8192,一个buffer header按512bytes。想让系统自动调整hash bucket的数量,需要将buffer cache大小调整为大于68M,计算方法如下:
SYS@ bys3>select 16384/2*(8192+512)/1024/1024 “Desired size” from dual;
Desired size
————
68
当然了,这种调整buffer cache大小进而增大hash bucket数量的方法是治标了,引起热链问题,不良SQL语句或者高并发是主因,要想从根本上解决热链问题,就要从这些方面入手解决了。–不过要真是buffer cache过小,还是要在系统内存资源允许情况下增大点好。
###########################
3.hash latch:就是latch:cache buffers chains –CBC LATCH
用于保护hash chain结构,一个CBC LATCH管理着多个hash chain。
用到此LATCH的场景:
1.服务进程需要扫描hash chain上的buffer header时或者叫要读取buffer cache中数据块,
2.服务器进程要将新读入的数据块挂载到hash chain上时,

我的测试系统中:hash_buckets 个数是16384 ,CBC LATCH数量是1024,计算出一个CBC LATCH要管理16个hash_chain

P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
—————————————- ————————————————– —————————— ——— ———- —–
_db_block_hash_buckets Number of database block hash buckets 16384 TRUE FALSE FALSE
_db_block_hash_latches Number of database block hash latches 1024 TRUE FALSE FALSE
SYS@ bys3>select count(*) from v$latch_children where name like ‘%cache buffers chains%’;
COUNT(*)
———-
1024
SYS@ bys3>select 16384/1024 from dual;
16384/1024
———-
16

#############################################################################

4.Data Buffer Cache多缓冲池技术:

指根据数据的不同访问方式,将Data Buffer Cache分为Default,Keep,Recycle. Default 池则存放未指定存储池 的数据,按照LRU算法管理。Keep 池中 数据倾向于一直保存,可存放经常使用的数据,Recycle池中数据倾向于即时老化,可以存放一次性读取使用的数据。默认所有表(未指定存储的池)使用Default池,大小是数据缓冲区大小。
创建或修改表进指定:alter table test storage(buffer_pool keep);
BUFFER_POOL { KEEP | RECYCLE | DEFAULT }
语句在10G官方文档-SQL Reference—alter table—storage_clause
ORACLE 9I后一个数据库可以存在2K/4K/8K/16K/32K这五种大小的block,db_block_size 定义的是主block_size。
如果要在数据库中创建不同block_size的表空间,就要设置db_nk_cache_size参数。
每个pool会有至少8个“Latch:cache buffers lru chain”.

5.working set:
每个working set都具有它自己的一组LRU和LRUW链表(LRU和LRUW链表总是成对出现的)。
ORACLE为了提高buffer cache性能(大内存),使用了多个working set
每个working set都由一个名为“Latch:cache buffers lru chain”的latch来保护,每一个lru latch对应一个working set。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。也就是说,当buffer cache加载一个新的数据块时,其对应的buffer header会去找一个可用的lru latch,如果没有找到,则再找下一个lru latch,直到找到为止。如果轮询完所有的lru latch也没能找到可用的lru latch,该进程只有等待latch free等待事件,同时出现在v$session_wait中,并增加“latch misses”。
如果启用了多个DBWR后台进程的话,每个DBWR进程都会对应一个不同的working set,而且每个DBWR只会处理分配给它的working set,不会处理其他的working set。

虚拟机中,CPU是一个,在10G中是有8个LRU LATCH,在11GR2中,是16个LRU LATCH.
SYS@ bys3>select * from v$version;
BANNER
——————————————————————————–
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 – Production
PL/SQL Release 11.2.0.4.0 – Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 – Production
NLSRTL Version 11.2.0.4.0 – Production

SYS@ bys3>@?/rdbms/admin/show_para
Enter value for p: lru_latch
old 3: WHERE i.inst_id = USERENV (‘Instance’) AND CV.inst_id = USERENV (‘Instance’) AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper(‘%&p%’) ORDER BY REPLACE (i.ksppinm, ‘_’, ”)
new 3: WHERE i.inst_id = USERENV (‘Instance’) AND CV.inst_id = USERENV (‘Instance’) AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper(‘%lru_latch%’) ORDER BY REPLACE (i.ksppinm, ‘_’, ”)

P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
—————————————- ————————————————– —————————— ——— ———- —–
_db_block_lru_latches number of lru latches 8 TRUE FALSE FALSE

BYS@ bys3>show parameter cpu_c
NAME TYPE VALUE
———————————— ———– ——————————
cpu_count integer 1
BYS@ bys3>select addr,child#,name from v$latch_children where name =’cache buffers lru chain’;

ADDR CHILD# NAME
——– ———- —————————————————————-
290A80DC 16 cache buffers lru chain
290A8058 15 cache buffers lru chain
297FC670 14 cache buffers lru chain
297FC5EC 13 cache buffers lru chain
297883B8 12 cache buffers lru chain
29788334 11 cache buffers lru chain
29714100 10 cache buffers lru chain
2971407C 9 cache buffers lru chain
2969FE48 8 cache buffers lru chain
2969FDC4 7 cache buffers lru chain
2962BB90 6 cache buffers lru chain
2962BB0C 5 cache buffers lru chain
295B78D8 4 cache buffers lru chain
295B7854 3 cache buffers lru chain
29543620 2 cache buffers lru chain
2954359C 1 cache buffers lru chain
SYS@ bys3>select id,name,block_size,current_size,target_size from v$buffer_pool;

ID NAME BLOCK_SIZE CURRENT_SIZE TARGET_SIZE
———- ——————– ———- ———— ———–
3 DEFAULT 8192 36 36
###################3
SYS@ ocm1>select * from v$version;
BANNER
—————————————————————-
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 – Prod
PL/SQL Release 10.2.0.1.0 – Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 – Production
NLSRTL Version 10.2.0.1.0 – Production

SYS@ ocm1>@?/rdbms/admin/show_para
Enter value for p: lru_latch
old 3: WHERE i.inst_id = USERENV (‘Instance’) AND CV.inst_id = USERENV (‘Instance’) AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper(‘%&p%’) ORDER BY REPLACE (i.ksppinm, ‘_’, ”)
new 3: WHERE i.inst_id = USERENV (‘Instance’) AND CV.inst_id = USERENV (‘Instance’) AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper(‘%lru_latch%’) ORDER BY REPLACE (i.ksppinm, ‘_’, ”)
P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
—————————————- ————————————————– —————————— ——— ———- —–
_db_block_lru_latches number of lru latches 8 TRUE FALSE FALSE

SYS@ ocm1>show parameter cpu_c
NAME TYPE VALUE
———————————— ———– ——————————
cpu_count integer 1
SYS@ ocm1>
SYS@ ocm1>select name from v$latch_children where name =’cache buffers lru chain’;
NAME
————————————————–
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
8 rows selected.

SYS@ ocm1>select id,name,block_size,current_size,target_size from v$buffer_pool;
ID NAME BLOCK_SIZE CURRENT_SIZE TARGET_SIZE
———- ——————– ———- ———— ———–
3 DEFAULT 8192 48 48

每个working set中,还有其它的队列:ckpt queue,ObjectQ、FileQ等,根据块的不同,也可能会同时挂载在这些队列下。
working set与lru latch一一对应。lru latch的数量是由一个隐藏参数:_db_block_lru_latches决定的。
该参数缺省值为DBWR进程的数量×8。该参数最小必须为8,如果强行设置比8小的数值,oracle将忽略你设置的值,而使用8作为该参数值。
###############################################
6.最后结合上图:用一段话来简洁的概括buffer cache的内存结构:

buffer cache中有pool,每个buffer pool使用自己的cache buffers lru chain LATCH,一个数据库实例可以配置:DEFAULT,2KB,4KB,8KB,16KB,32KB,KEEP,RECYCLE 这8种类型的buffer pool,故cache buffers lru chain LATCH的数量最少为8个。每个Latch:cache buffers lru chain对应着一个working set,
每个working set中,有多个CBC LATCH来,每个CBC LATCH管理着多个hash bucket,每个hash bucket对应着一条hash chain。
数据块在读入buffer cache中时,同时会在buffer cache中构造一个buffer header,ORACLE对数据块的DBA进行hash运算,根据运算结果将buffer header挂载到相应的hash chain上。
同时,每个working set中,有一对LRU和LRUW链表,buffer cache中的数据块,胜块会挂载到LRUW链表,其它块在LRU链表。也就是buffer cache中的数据块,肯定在LRU和LRUW链表之一:不能同时存在这两个链表上。

buffer cache实验1-内存结构图解