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日
文字:韵筝