这篇文章是参考甲骨论老相老师的教学视频:
http://v.youku.com/v_show/id_XMzkyMjA4NDM2.html
所做学习笔记
1. 什么是buffer
之前提过很多次啦, 其实在oracle数据文件中最小的单位就是block, 而用户读取block数据时,oracle就会将block的数据放入缓存,那么缓存中对应block的单位就叫buffer了, block的大小与buffer大小是一样的.
2. 关于buffer的动态数据字典x$dh
Oracle有一个动态视图x$dh, 里面有很多个数据行, 其中每个数据行对应buffer_cache里的每1个buffer..
x$bh里有很多列, 这次我们重点讲解几个重要的字段啦:
SQL> desc x$bh
Name Null? Type
----------------------------------------- -------- ----------------------------
ADDR RAW(8)
INDX NUMBER
INST_ID NUMBER
HLADDR RAW(8)
BLSIZ NUMBER
NXT_HASH RAW(8)
PRV_HASH RAW(8)
NXT_REPL RAW(8)
PRV_REPL RAW(8)
FLAG NUMBER
FLAG2 NUMBER
LOBID 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(8)
DIRTY_QUEUE NUMBER
SET_DS RAW(8)
OBJ NUMBER
BA RAW(8)
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(8)
US_PRV RAW(8)
WA_NXT RAW(8)
WA_PRV RAW(8)
OQ_NXT RAW(8)
OQ_PRV RAW(8)
AQ_NXT RAW(8)
AQ_PRV RAW(8)
OBJ_FLAG NUMBER
TCH NUMBER
TIM NUMBER
CR_RFCNT NUMBER
SHR_RFCNT NUMBER
3. Buffer 的 state (就是上面的state 字段啦)
查看当前的状态, 如下图 只有3个值..
每种值的意思如下面表
下面解释这几种状态意思
3.1 Free
就是未被使用过的buffer啦, 好容易理解~
3.2 XCUR
字面意思就是当前实例独享的当前模式块, 其中重点要留意current的意思.
如上图 当1个server process要读取dbf文件中的1个block时,必然会将这个block数据放入buffer cache中, 那么buffer cache里那个对应buffer就被占用了, 状态的就成了为current.
CUR状态的buffer肯定有1个dbf文件文中的中的block与其对应的.
在单实例里, CUR状态的buffer肯定就是XCUR,因为不可能被其他实例共享啦.
3.3 SCUR
字面意思就是与其他实例共享的CUR状态的buffer, 在RAC集群数据库会出现这种block, 老相老师视频里没有深讲,以后再补充了.
个人猜测因为RAC是有个多个实例的, 也就代表有多个SGA, 也就是多个Buffer cache, 既然其中1个buffer cache有了这个CUR的buffer, 其他实例的Buffer cache就没必要重复了, 可以共享给其他实例的server process访问?
3.4 CR
当1个CUR buffer被其中1个server process修改, 但是并没有提交. 如果下一个server process访问这个buffer时,就会形成脏读了.
为了避免这种情况, 下1个server process发现要访问的CUR buffer已被其他server process修改后而未提交时,就会在buffer cache里申请多1个空间, 复制1个修改前的buffer 镜像, 这个buffer 就叫做CR块.
如下图, 当buffer cache里的1个buffer被修改且未提交时, 下个buffer是不能访问的.
这时Server process B会申请1个新的buffer空间, 复制要访问的buffe到1个新的空间, 但是还要把这个buffer修改后的数据还原回去. 这时,重做日志就发挥作用了, 因为server process A修改数据后即使没有提交, 但是一样会产生重做日志的, server process B就会利用这些重做日志, 改动回滚, 就形成1个新的CR块了. 如下图:
要注意如下几点:
1. 上面提到1个CUR块是与1个数据文件中的block一一对应的, 而CR块作为镜像,是没有dbf中的block与其对应..
2. 也就是说对与dbf文件中1个block来讲,只会存在1个CUR块.
3. Server process只能对CUR buffer作修改, 而不能修改CR块.
也就是说对于1个同1行数据不能有两个session同时修改, 假如1行数据的值是x ,其中1个会话执行x+y, 另1个同时执行x+z,这时会话1先提交, 那么值就变成x+y了. 但是会话2再提交时, 值变成x+z了, 所以最后丢失了y的数据.
3.5 READ
这个也很容易理解, 就是正在读取当中的状态啦, 因为从dbf文件中1个block读取数据到buffer cache里的1个buffer时, 会发生物理IO, 假如这个过程需要10毫秒, 那么在这10毫米中这个buffer状态就是READ.
3.6 XREC
这个buffer 处于介质恢复状态中.
3.7 IREC
这个buffer 处于实例恢复状态中.
关于XREC和IREC状态以后再详细讨论, 在Oracle正常使用中是不会出现这两种状态的buffer的.
4. 做个例子啦
步骤1:首先查看一下HR.CL_DEPT这张表, 有6行数据啦~
步骤2: 跟住清空buffer_cache里的数据, 注意在生产中执行这个动作很危险, 因为跟住就会有大量的物理IO了.
步骤3: 执行下面sql语句, 能查询某个数据库 对象的buffer占用状态:
select o.object_name,
decode(state, 0, 'free', 1, 'xcur' , 2, 'scur', 3, 'cr',
4, 'read', 5, 'mrec' , 6, 'irec', 7, 'write',
8, 'pi') as state,
count(1) blocks
from x$bh b, dba_objects o
where b.obj = o.data_object_id
and o.object_name = 'CL_DEPT'
and o.owner = 'HR'
group by o.object_name, state
order by blocks desc;
执行一下:
可以见到这个表还占用5个buffer ,但是状态是free的, 所以这个5个buffer是没有数据的.
那为什么会占住5个free呢, 是因为我们刚才select过一次, 即使执行清空buffer cache,但是在CRC链区可能还存在buffer的头部信息指向, 但是buffer数据就的确被清空了.
隔2分钟再看一次:
发现只占用4个free了, 所以CRC链里的信息也会慢慢清除的.
步骤4: 进行select 操作, 然后再查看buffer状态
首先select一下这个张表, 因为buffer里并没有这张表的缓存,所以会发生物理IO啦:
这时查看buffer状态:
见到6个 xcur buffer了, 也说明有6个block的被写入到buffer cache里面
步骤5: 用当前session (SYS 帐号)修改一条数据, 但并不提交
步骤6: 用另1个session (scott 帐号)查看这张表, 看到的是修改前的数据
步骤7: 只所以会见到修改前的数据, 是因为构造了CR块啦!
步骤8: SYS这个session提交修改, 然后scott 在查看1次表, 见到修改后的数据.
步骤9: 再查看buffer 状态
发现CR 块并不会马上消失哦
http://v.youku.com/v_show/id_XMzkyMjA4NDM2.html
所做学习笔记
1. 什么是buffer
之前提过很多次啦, 其实在oracle数据文件中最小的单位就是block, 而用户读取block数据时,oracle就会将block的数据放入缓存,那么缓存中对应block的单位就叫buffer了, block的大小与buffer大小是一样的.
2. 关于buffer的动态数据字典x$dh
Oracle有一个动态视图x$dh, 里面有很多个数据行, 其中每个数据行对应buffer_cache里的每1个buffer..
x$bh里有很多列, 这次我们重点讲解几个重要的字段啦:
SQL> desc x$bh
Name Null? Type
----------------------------------------- -------- ----------------------------
ADDR RAW(8)
INDX NUMBER
INST_ID NUMBER
HLADDR RAW(8)
BLSIZ NUMBER
NXT_HASH RAW(8)
PRV_HASH RAW(8)
NXT_REPL RAW(8)
PRV_REPL RAW(8)
FLAG NUMBER
FLAG2 NUMBER
LOBID 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(8)
DIRTY_QUEUE NUMBER
SET_DS RAW(8)
OBJ NUMBER
BA RAW(8)
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(8)
US_PRV RAW(8)
WA_NXT RAW(8)
WA_PRV RAW(8)
OQ_NXT RAW(8)
OQ_PRV RAW(8)
AQ_NXT RAW(8)
AQ_PRV RAW(8)
OBJ_FLAG NUMBER
TCH NUMBER
TIM NUMBER
CR_RFCNT NUMBER
SHR_RFCNT NUMBER
3. Buffer 的 state (就是上面的state 字段啦)
查看当前的状态, 如下图 只有3个值..
每种值的意思如下面表
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
下面解释这几种状态意思
3.1 Free
就是未被使用过的buffer啦, 好容易理解~
3.2 XCUR
字面意思就是当前实例独享的当前模式块, 其中重点要留意current的意思.
如上图 当1个server process要读取dbf文件中的1个block时,必然会将这个block数据放入buffer cache中, 那么buffer cache里那个对应buffer就被占用了, 状态的就成了为current.
CUR状态的buffer肯定有1个dbf文件文中的中的block与其对应的.
在单实例里, CUR状态的buffer肯定就是XCUR,因为不可能被其他实例共享啦.
3.3 SCUR
字面意思就是与其他实例共享的CUR状态的buffer, 在RAC集群数据库会出现这种block, 老相老师视频里没有深讲,以后再补充了.
个人猜测因为RAC是有个多个实例的, 也就代表有多个SGA, 也就是多个Buffer cache, 既然其中1个buffer cache有了这个CUR的buffer, 其他实例的Buffer cache就没必要重复了, 可以共享给其他实例的server process访问?
3.4 CR
当1个CUR buffer被其中1个server process修改, 但是并没有提交. 如果下一个server process访问这个buffer时,就会形成脏读了.
为了避免这种情况, 下1个server process发现要访问的CUR buffer已被其他server process修改后而未提交时,就会在buffer cache里申请多1个空间, 复制1个修改前的buffer 镜像, 这个buffer 就叫做CR块.
如下图, 当buffer cache里的1个buffer被修改且未提交时, 下个buffer是不能访问的.
这时Server process B会申请1个新的buffer空间, 复制要访问的buffe到1个新的空间, 但是还要把这个buffer修改后的数据还原回去. 这时,重做日志就发挥作用了, 因为server process A修改数据后即使没有提交, 但是一样会产生重做日志的, server process B就会利用这些重做日志, 改动回滚, 就形成1个新的CR块了. 如下图:
要注意如下几点:
1. 上面提到1个CUR块是与1个数据文件中的block一一对应的, 而CR块作为镜像,是没有dbf中的block与其对应..
2. 也就是说对与dbf文件中1个block来讲,只会存在1个CUR块.
3. Server process只能对CUR buffer作修改, 而不能修改CR块.
也就是说对于1个同1行数据不能有两个session同时修改, 假如1行数据的值是x ,其中1个会话执行x+y, 另1个同时执行x+z,这时会话1先提交, 那么值就变成x+y了. 但是会话2再提交时, 值变成x+z了, 所以最后丢失了y的数据.
3.5 READ
这个也很容易理解, 就是正在读取当中的状态啦, 因为从dbf文件中1个block读取数据到buffer cache里的1个buffer时, 会发生物理IO, 假如这个过程需要10毫秒, 那么在这10毫米中这个buffer状态就是READ.
3.6 XREC
这个buffer 处于介质恢复状态中.
3.7 IREC
这个buffer 处于实例恢复状态中.
4. 做个例子啦
步骤1:首先查看一下HR.CL_DEPT这张表, 有6行数据啦~
步骤3: 执行下面sql语句, 能查询某个数据库 对象的buffer占用状态:
select o.object_name,
decode(state, 0, 'free', 1, 'xcur' , 2, 'scur', 3, 'cr',
4, 'read', 5, 'mrec' , 6, 'irec', 7, 'write',
8, 'pi') as state,
count(1) blocks
from x$bh b, dba_objects o
where b.obj = o.data_object_id
and o.object_name = 'CL_DEPT'
and o.owner = 'HR'
group by o.object_name, state
order by blocks desc;
执行一下:
可以见到这个表还占用5个buffer ,但是状态是free的, 所以这个5个buffer是没有数据的.
那为什么会占住5个free呢, 是因为我们刚才select过一次, 即使执行清空buffer cache,但是在CRC链区可能还存在buffer的头部信息指向, 但是buffer数据就的确被清空了.
隔2分钟再看一次:
发现只占用4个free了, 所以CRC链里的信息也会慢慢清除的.
步骤4: 进行select 操作, 然后再查看buffer状态
首先select一下这个张表, 因为buffer里并没有这张表的缓存,所以会发生物理IO啦:
这时查看buffer状态:
见到6个 xcur buffer了, 也说明有6个block的被写入到buffer cache里面
步骤5: 用当前session (SYS 帐号)修改一条数据, 但并不提交
步骤6: 用另1个session (scott 帐号)查看这张表, 看到的是修改前的数据
步骤7: 只所以会见到修改前的数据, 是因为构造了CR块啦!
步骤9: 再查看buffer 状态
发现CR 块并不会马上消失哦