oracle学习笔记 buffer状态深入剖析

本文深入解析Oracle数据库中Buffer Cache的工作原理,重点介绍了X$BH表的结构及其与Buffer状态的关系,详细阐述了Free、XCUR、SCUR、CR、Reading、MREC、IREC等状态的含义,并通过实例演示了如何查询Buffer的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



oracle学习笔记  buffer状态深入剖析


这节课把buffercache里面的buffer的几个状态给大家讲一下
以对buffer有更深的了解

dbf的数据块在物理磁盘上叫block
内存里面都叫buffer


一)x$bh表


数据库中有个表x$bh
翻译为buffer header表
这个表里面每一行数据都对应着
buffercache里的一个buffer


也就是每一个在buffercache的块在x$bh里面都有一个行和它对应
所以我们研究buffercache就研究x$bh就可以


先看一下这个表有多少列
开始老师输出数据的格式未设置好,结果有些乱
所以要设置sql语法语句数据输出格式
在sqlplus命令行环境提供了很多额外的非sql语法命令
其中有column


这里老师输入了
column name format a10
命令
是sqlplus命令行格式化输出的常用命令之一
执行后只在执行了它的会话中生效


column主要格式化列的显示形式
用这个命令可以更改select语句中
指定列的输出宽度、改变缺省的列标题、设置列标题的对齐方式等一些输出格式
上面语句将在select语句中列字段name输出时的格式设置为文字型,且占10个字符宽度
如果输出超出10个字符此列会多行显示,但仍然是每行10个字符
是为了使结果输出工整,如果输出结果可看,这个命令可以不用
此命令执行后,以后的执行的每个select语句,
只要输出中有name字段,name字段的显示都是10个字符宽度


但column对desc语句的输出没有作用
因为desc和column同样都不属于sql语法,是sqlplus命令行的命令
column的作用范围是sql语法内的输出结果


所以老师使用了前面讲过的sqlplus的另一个格式化命令set linesize使结果有序
它对在sqlplus中执行的所有命令都有效


SQL> desc x$bh
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ADDR                                               RAW(4)
 INDX                                               NUMBER
 INST_ID                                            NUMBER
 HLADDR                                             RAW(4)
 BLSIZ                                              NUMBER
 NXT_HASH                                           RAW(4)
 PRV_HASH                                           RAW(4)
 NXT_REPL                                           RAW(4)
 PRV_REPL                                           RAW(4)
 FLAG                                               NUMBER
 RFLAG                                              NUMBER
 SFLAG                                              NUMBER
 LRU_FLAG                                           NUMBER
 TS#                                                NUMBER
 FILE#                                              NUMBER
 DBARFIL                                            NUMBER
 DBABLK                                             NUMBER
 CLASS                                              NUMBER
 STATE                                              NUMBER
 MODE_HELD                                          NUMBER
 CHANGES                                            NUMBER
 CSTATE                                             NUMBER
 LE_ADDR                                            RAW(4)
 DIRTY_QUEUE                                        NUMBER
 SET_DS                                             RAW(4)
 OBJ                                                NUMBER
 BA                                                 RAW(4)
 CR_SCN_BAS                                         NUMBER
 CR_SCN_WRP                                         NUMBER
 CR_XID_USN                                         NUMBER
 CR_XID_SLT                                         NUMBER
 CR_XID_SQN                                         NUMBER
 CR_UBA_FIL                                         NUMBER
 CR_UBA_BLK                                         NUMBER
 CR_UBA_SEQ                                         NUMBER
 CR_UBA_REC                                         NUMBER
 CR_SFL                                             NUMBER
 CR_CLS_BAS                                         NUMBER
 CR_CLS_WRP                                         NUMBER
 LRBA_SEQ                                           NUMBER
 LRBA_BNO                                           NUMBER
 HSCN_BAS                                           NUMBER
 HSCN_WRP                                           NUMBER
 HSUB_SCN                                           NUMBER
 US_NXT                                             RAW(4)
 US_PRV                                             RAW(4)
 WA_NXT                                             RAW(4)
 WA_PRV                                             RAW(4)
 TCH                                                NUMBER
 TIM                                                NUMBER

这个表中有很多列,不可能一次研究完
有些列需要重点关注
如TCH、FLAG、RFLAG、HLADDR
这里我们看STATE列


二)buffer的状态


在x$bh表中STATE列
它应该是有8种值


摘自老师教案:
state:

0, FREE, no valid block image
1, XCUR, a current mode block, exclusive to this instance
2, SCUR, a current mode block, shared with other instances
3, CR, a consistent read (stale) block image
4, READ, buffer is reserved for a block being read from disk
5, MREC, a block in media recovery mode
6, IREC, a block in instance (crash) recovery mode


对它的翻译是:
FREE(0)=还没有使用过的块;
XCURRENT(1)=实例以排他方式获取的当前模式数据块,正在被当前的instance独占
SCURRENT(2)=可以与其他实例共享的当前模式数据块,正在被当前的instance共享
CR(3)=作为一致性读镜像的数据块,永远不会被写入磁盘;
READING(4)=正在从磁盘读出的数据块;
MRECOVERY(5)=正在进行介质恢复的数据块;
IRECOVERY(6)=正在进行实例恢复的数据块。


我们简单select一下
SQL> select distinct state from x$bh;

     STATE
----------
         1
         3
         0
说面目前这个表中
state只有0 1 3这三个值
只用到了三个值
说明现在数据库中的buffer只有这三个状态


1)free state


0号状态是FREE
对某个buffer来讲它从来没有被用过、还没有和block对应就是free


2)current state和cr state


XCUR SCUR CR三个理解有一定的难度
1号状态是XCUR


假设现在要读一个block
这个块在buffercache里面没有
就把它读到buffer中去
计算以后把它放到一个buffer里面
这个在buffercache中的buffer就叫CUR:current块,叫当前块
一个block读进一个buffer就叫current块


current块和cr(consistent read读一致性)块是有对应的


有一个a会话连接上以后对buffer块里的某个行进行修改
修改完了以后没有提交
这时候b会话上来以后读这个buffer块
这时b想要读这个块这个块又被a修改了但是还没有提交
b不能读到a没有提交的修改
b就会在另外一个位置申请一个buffer块
然后把这个块里面没有修改的写到新申请块
已经修改的它把修改前的值在undo里面找到
写入新块,构造出一个cr块
然后b就读cr块
这就是cr块


但是这个cr块和原始block没有对应关系
b构造这个块以后把数据读出来了
读出来以后这个块马上就没用了
cr块马上就没有意义了


会话a操作的块是current块
它永远和原始block块是对应的,无论是修改前后
此buffer干净状态和脏状态都是current块
cr块是会话b要读这个块但这个块不能直接读就构造一个cr块
这个cr块是临时的
读完以后这个块马上就没有意义了
马上就可以被覆盖了


我们修改一个块只能修改current块


总结
1、我们要对一个块进行增删改
无论在这个块里面增加行、删除行还是要修改行
我们只能修改current块只能对current块进行处理
2、读的时候
current块里面没有未提交的操作直接读current就可以了
current里有未提交的,在其它会话中我们只能构造一个cr块


3)XCUR state和SCUR state


这地方有人理解有误,在网上各种各样的写法都有


current状态还分XCUR和SCUR
X是exclusive(独占的)的缩写
S是shared(共享的)的缩写


我们讲过一个数据库一般都有一个实例
但是也有一个数据库对应多个实例


一个数据库对应一个实例的情况下也就是在非RAC的环境下
current永远都用XCUR也就是只有XCUR
因为这个buffer块被这个实例独占


如果在存在RAC的环境里面才有可能出现SCUR
RAC中有Cache Fusion(融合)即内存融合技术
也叫PCM:Parallel Cache Management并发内存管理
SCUR在Cache Fusion技术机制会用到
因为它需要和其它进程分享这个buffer块


在单实例环境里面
current只有一种情况就是XCUR
SCUR在非RAC环境下是没有的


4)read state


也是数据块的一个状态


block要读到内存里的buffer里面去
读的过程中要发生物理io
物理io需要花费时间把block块读到buffer里面去如读了10ms
这个buffer在这个10ms里面就处于一个read状态


read state就是block正在把数据写入到buffer里面去


5)MREC state,IREC state


这里
M是media(介质)
I是instance(实例)
REC是recovery(恢复)


MREC是介质恢复
IREC是实例恢复


在oracle的备份恢复中才能用到
在正常的数据库启动过程中或数据库使用过程中
一般不会出现MREC state和IREC state的情况


状态号0、1、2、3、4出现的情况比较多


6)第8种状态write state


就是写状态


块脏了时间长了以后DBWn进程会把它写到磁盘上
把它向磁盘写的过程,状态就是wirte
和读是对应的


对我们来讲最经常运行的状态是读写
再就是free、xcur和cr这几种状态


这就是与block对应的buffer的几种状态



三)查询块状态的例子


举一个例子
现在有个表t2
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun

t2现在有两个数据行


然后
SQL> alter system flush buffer_cache;

System altered.


这是将整个buffercache全部清空
这样可以清楚的看到sql语句生成的buffer的个数和状态
但这在生产中是比较危险的
因为你全部清空以后接着会发生大量的物理io


使用下面语句
select
o.object_name,
decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
6,'irec',7,'write',8,'pi') state,
count(*) blocks
from x$bh b, dba_objects o
where b.obj = o.data_object_id
and o.object_name = 'T2'
group by o.object_name, state
order by blocks desc;
能查一个对象所占用buffer的情况


我们查t2表
SQL> select
o.object_name,
decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
  2    3    4  6,'irec',7,'write',8,'pi') state,
  5  count(*) blocks
  6  from x$bh b, dba_objects o
  7  where b.obj = o.data_object_id
  8  and o.object_name = 'T2'
  9  group by o.object_name, state
 10  order by blocks desc;

OBJECT_NAME
----------------------------------------------------------------------------------------------------
STATE     BLOCKS
----- ----------
T2
free           2


目前t2虽然占了2个块但是这2个状态是free
这种占用的块是free的状态很可能和刚清空了buffer_cache有关
也就是t2根本没有占用buffer


这种情况是一个buffer被清空了
但这个链的地方还挂着一个头指向它
即使这时buffer的状态是free state
这是它在清空的过程中不太彻底的一个表现


现在我们再来读一下这个表
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun


就读t2这个表了只是读


再执行一下
SQL> select
o.object_name,
  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
  4  6,'irec',7,'write',8,'pi') state,
  5  count(*) blocks
  6  from x$bh b, dba_objects o
  7  where b.obj = o.data_object_id
  8  and o.object_name = 'T2'
  9  group by o.object_name, state
 10  order by blocks desc;

OBJECT_NAME
----------------------------------------------------------------------------------------------------
STATE     BLOCKS
----- ----------
T2
xcur           2

T2
free           2


结果中t2占了两个块是xcur
对这个块读的话也是xcur
free的两个块不是真实的它并没有占用


执行语句:
SQL> update t2 set name='jiagulunoracle' where id=1;


1 row updated.
对表进行更新


另外再启一个会话


执行
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun
这时应该产生cr块了应该会产生


在查一下t2表块的状态
SQL> select
o.object_name,
  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
  4  6,'irec',7,'write',8,'pi') state,
  5  count(*) blocks
  6  from x$bh b, dba_objects o
where b.obj = o.data_object_id
  7    8  and o.object_name = 'T2'
group by o.object_name, state
  9   10  order by blocks desc;

OBJECT_NAME
----------------------------------------------------------------------------------------------------
STATE     BLOCKS
----- ----------
T2
xcur           2

T2
cr             2

T2
free           1
产生了两个cr块
在两个会话中查询结果都一样


然后在会话2中
多次执行select * from t2;
每次执行后立即查询t2表的块的状态
可以看到这时对应的cr块会有增加,
但此数值没有无限制的增加,
用上面方法试验了多个不同表发现每个表对应的cr块最多只增加到5
说明cr块在数据读出来以后马上就失效了,再次查询还要构造新的cr块。
在查询过程中对应cr状态块没有减少,只是说明系统还没有回收。
构造的cr块有上限值,说明oracle系统对它有限制


db buffer中对于一个block块默认情况下最多可以保留6个cr读一致性块
这个值的大小由隐藏参数_db_block_max_cr_dba决定
它的解释是 Maximum Allowed Number of CR buffers per dba
默认值是6包含5个CR块和1个XCUR块


使用
SQL> show parameter _db_block_max_cr_dba
查它的值没有结果


oracle的隐藏参数字典是 x$ksppi和x$ksppcv基表
查询这个隐藏参数需用
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM x$ksppi x, x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND x.ksppinm LIKE '%_db_block_max_cr_dba%'
语句
结果
NAME                 VALUE DESCRIB
-------------------- ----- --------------------------------------------------
_db_block_max_cr_dba 6     Maximum Allowed Number of CR buffers per dba
oracle给的值为6说明每个block块在CBC链上对应最多只能挂6个CR块
实际测试最多有5个CR块另外1个为XCUR块


在执行了update命令的会话中将工作进行提交
SQL> commit;

Commit complete.


然后在两个会话中查询


SQL> select
o.object_name,
  2    3  decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',
6,'irec',7,'write',8,'pi') state,
  4    5  count(*) blocks
  6  from x$bh b, dba_objects o
  7  where b.obj = o.data_object_id
  8  and o.object_name = 'T2'
  9  group by o.object_name, state
 10  order by blocks desc;

OBJECT_NAME
--------------------------------------------------------------------------------
STATE     BLOCKS
----- ----------
T2
cr             4

T2
xcur           2
结果中还有cr块说明它仍挂在CBC链上但已经失去了意义,等着被再利用。


常见的三个状态free、cr、xcur的都有了



这节讲了buffer的状态以及如何去判断buffer的状态



2016年9月25日

                                          文字:韵筝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值