首先说明_fairness_threshold参数仅在RAC环境下才有意义,让我对这个参数引起关注是在某一次查询v$cr_block_server时,发现该视图有一个名为FAIRNESS_DOWN_CONVERTS的字段,官方文档里将其解释为:Number of times an instance receiving a request has down-converted an X lock on a block because it was not modifying the block
该参数相关性能指标在AWR的"Global CR Served Stats"章节里也有出现:
根据我的理解,将FAIRNESS_DOWN_CONVERTS的含义翻译为:RAC环境下的实例A对某个block在buffer cache里加上了Exclusive锁,但实例A此时并没有在修改该block,实例B请求从实例A的buffer cache里读访问这个block,实例A接收到请求后先将这个block上的Exclusive锁降级转换后再传输给实例B,降级转换一次,FAIRNESS_DOWN_CONVERTS值就+1。
要完全理解上述概念,我们至少需要搞清楚以下几个问题:
1、实例B为何要从实例A的buffer cache里访问这个block?
2、实例A既然没有在修改这个block,为何会对block持有Exclusive锁?
3、锁降级转换目的在于?是否每一次跨实例传输block前都需要先进行锁降级转换?
逐个问题进行解答:
1、实例B为何要从实例A的buffer cache里访问这个block?
RAC里所有实例的buffer cache通过高速专网进行互联,Cache Fusion机制将各实例的buffer cache在逻辑上聚合成一个整体,当某个实例要访问的block已被其它实例访问过且仍保留在那个实例的bffer cache里时,只要block的内容能够满足请求实例的访问要求,该block就会通过高速专网从持有实例的buffer cache传输到请求实例的buffer cache里,避免了请求实例从磁盘进行读取。这之中有一个重要前提必须满足,那就是保证持有实例block的内容是适合传输给请求实例的。换而言之,实例A要读取的block在实例B的buffer cache里,但若实例B Buffer cache里的内容是N久之前的版本,这时实例A就只能从磁盘读取了,异或者实例C的Buffer Cache拥有该block的较新版本,那么实例A就会舍弃实例B和磁盘而从实例C读取。如何为实例A选择最为合适的数据源,确保其能快速得到准确的查询结果?一切尽在Global Resource Directory,简称GRD,只在RAC里才有的GRD其实就是SGA里的一块内存区域存放内容包括了Global enqueue resource和Global cache resources,每个实例buffer cache里的block就属于global cache resource,每个block都有自己的master node,master node上的GRD里准确记录了这个block版本生成时的SCN、各节点持有的block锁类型等信息,可以通过gv$ges_resource视图查看block的master node是那个,比如对于scott.t0820_1表所在的block 6/255,其master_node为实例1:
select dbms_rowid.rowid_relative_fno(rowid) rfno,dbms_rowid.rowid_block_number(rowid) blkno from scott.t0820_1;
RFNO BLKNO
---------- ----------
6 255
select to_char(6,'xxx'),to_char(255,'xxx') from dual;
TO_C TO_C
---- ----
6 ff
select inst_id,resource_name,ON_GRANT_Q,ON_CONVERT_Q,master_node from gv$ges_resource where resource_name like '[0xff][0x6],[BL]%';
INST_ID RESOURCE_NAME ON_GRANT_Q ON_CONVERT_Q MASTER_NODE
---------- ------------------------------ ---------- ------------ -----------
1 [0xff][0x6],[BL][ext 0x0,0x0] 1 0 0 <---master_node=0表示实例1
假设一个四节点的RAC环境,block 6/255 存在于实例2的buffer cache里,也存在于实例4的buffer cache里,当实例3要查询这个block时,先根据特定的hash算法找到block的master node也就是实例1,实例1访问自己的GRD后得知实例2 buffer cache里的block刚修改过其SCN号比实例4里的要大,而比实例3查询发起时的SCN要小,所以实例1通知node 2将block传输给实例3,大致过程如下图所示:
① S实例3要查询block 6/255的内容,经过一定的hash算法得出block 6/255的master node是实例1,于是实例3向实例1发起查询block 6/255,此时的Query SCN=107
② 实例1查询GRD后得知实例2上存在的block 6/255版本比实例4更新,更适合作为结果传递给实例1,所以实例1通知实例2要求其将该block传输给实例3
③ 实例2将自己buffer cache里的block 6/255传输给实例3
RAC环境的各个实例都会存放一部分GRD信息,具体位置是在shared pool里,可以使用下面的语句了解这部分的内存占用情况:
SELECT name,bytes FROM v$sgastat WHERE name LIKE 'ges resource%' OR name LIKE 'ges enqueues';
NAME BYTES
-------------------------- ----------
ges resource pools 744
ges resource hash seq tab 16384
ges enqueues 11550936
ges resource 5708880
ges resource hash table 720896
2、实例A既然没有在修改这个block,为何会对block持有Exclusive锁?
和单实例数据一样,多实例的RAC环境下对block的访问也需要获得各种锁,单实例与多实例锁的对应关系如下:
单实例 多实例
NULL KJUSERNL
RS KJUSERCR
RX KJUSERCW
S KJUSERPR
SRX KJUSERPW
X KJUSEREX
其中KJUSERPR表示Protected read,KJUSEREX表示One process holds exclusive lock,我们暂只关注这两种锁。
通过一个小实验来了解一下KJUSERPR和KJUSEREX在什么情况下会出现
实例1:
create table scott.t0820_1 (id number);
insert into scott.t0820_1 values(1);
commit;
select * from scott.t0820_1;
ID
----------
1
select distinct dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) blkno from scott.t0820_1;
FNO BLKNO
---------- ----------
6 255
alter system flush buffer_cache;
update scott.t0820_1 set id=2 where id=1;
commit;
set heading on
select inst_id,file#,block#,status from gv$bh where file#=6 and block#=255 and status!='free';
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 255 xcur
1 6 255 cr
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_8474.trc
alter system dump datafile 6 block 255;
在dump文件susedb11_ora_8474.trc的尾端可以看到block 6/255在GRD里的部分信息:
GLOBAL CACHE ELEMENT DUMP (address: 0x8afaeaa8):
id1: 0xff id2: 0x6 pkey: OBJ#15976 block: (6/255)
lock: X rls: 0x0 acq: 0x0 latch: 4 <---注意这里lock: X代表了block上锁类型为KJUSEREX
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xadf5b3b0,0xadf5b3b0]
seq: 18 hist: 58 145:0 28 340 66 144:0 7 352 197 48 121 113 424
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02000001 state: XCURRENT tsn: 6 tsh: 2
addr: 0xadf5b278 obj: 15976 cls: DATA bscn: 0x0.186dfc
在update语句commit后我们看到buffer cache里出现了block 6/255的两个版本,标示为cr的是update之前的before-image,标示为xcur的正是修改后的最新版本,xcur表示exclusive current,说明该block刚被更新过,buffer cache和磁盘上的内容可能不一样(checkpoint尚未发生)也有可能已经一样了(已发生checkpoint)。从上面的这段实验内容可以看出尽管update所在事务已经提交但实例1还是持有着block 6/255上的exclusive锁,虽然没有释放,但并不会影响其它实例对于block 6/255的访问,后面会有对这个问题的解释。
alter system flush buffer_cache;
select * from scott.t0820_1;
ID
----------
2
select inst_id,file#,block#,status from gv$bh where file#=6 and block#=255 and status!='free';
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 255 scur
第二次flush buffer cache后紧接着作一次查询,观察到 block 6/255在buffer cache里的类型变为了scur,scur表示shared current,说明该block在buffer cache和磁盘里的内容一致。
再次dump后可以看到block上的锁相应变成了Lock: S
alter system dump datafile 6 block 255;
GLOBAL CACHE ELEMENT DUMP (address: 0x8afaeaa8):
id1: 0xff id2: 0x6 pkey: OBJ#15976 block: (6/255)
lock: S rls: 0x0 acq: 0x0 latch: 4 <---lock: S
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh01: kdstgr'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xa9f1c290,0xa9f1c290]
seq: 28 hist: 66 144:0 7 352 197 48 121 113 424 180 58 145:0 28
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x00080000 state: SCURRENT tsn: 6 tsh: 1
addr: 0xa9f1c158 obj: 15976 cls: DATA bscn: 0x0.186dfc
这个小实验说明,最后修改过某个block的实例即便事务已经提交仍会在这个block上留下Exclusive锁,当然这个Exclusive锁是可以转换成其它类型的,比如在checkpoint后会被scur取代
3、锁降级转换目的在于?是否每一次跨实例传输block前都需要先进行锁降级转换?
锁降级转换指的是buffer cache中的block状态从xcur转换为scur,考虑一下这个场景:
实例3为block A的master node,实例1会话修改了block A,此事实例1对block A持有Exclusive锁,在v$bh里的buffer类型是xcur,之后实例2会话把select访问Block A的请求递交给实例3,实例3根据GRD里的资源信息发现实例1 buffer cache里的block A的xcur版本能满足实例2的查询要求,于是通知实例1将其buffer cache里的block A传送给实例2,按照一般的思路,实例1在向实例2传输前需要将Exclusive锁转换成Share模式的锁(因为实例2是select访问),然后再传输给实例2。但考虑到既然实例1修改了block A,其再次修改Block A的可能性还是很大的,如果将Exclusive锁转换成Share锁,后续实例1再次修改block A时又需要从Share转回Exclusive,在维护GRD的层面还是会产生不少开销的。所以实例1在首次将block A传送给实例2时并不会将其持有Exclusive锁释放或者转换成其它类型,而是基于xcur类型的block A版本构造出一个类型为cr的buffer(内容与xcur类型的buffer完全一样),将这个cr block传送到实例2的buffer cache里,实例2访问cr block时无需加任何的锁,但oracle为了加以区分还是上了一个NULL类型的锁,准确的说它是一个placeholder类型的lock,在GRD里这个锁的名字是KJUSERNL。这种处理方式显然能够保留实例1对block持有的Exclusive锁。但为此产生的代价是:从xcur构造出cr类型的block也是会产生一定开销的,这其中包括
(1) build cr block的时间
(2) build cr block过程中产生的redo写入online redolog的时间
一种较为极端的情况是若实例2后面对同一个block连续发起多次select操作,会引发实例1多次构造cr block的动作。于是Oracle在保留Exclusive锁与构造cr block间作了一个折衷,提供了隐含参数_fairness_threshold,当select访问次数达到参数指定值的时候,实例1会将block上的Exclusive锁降级转换成Shared锁,对应的buffer也会从xcur转换成scur类型,当实例2第_fairness_threshold+1次访问相同block的时候实例1会把scur类型的block传输到实例2,之后实例2再次访问相同block就只要从本地Buffer cache获取。
我们还是通过具体实验来体会一下_fairness_threshold参数的作用,其中需要用到的rec.sql脚本内容如下:
***************
* rec.sql脚本内容
***************
set heading off
select '----gv$cr_block_server----' from dual;
set heading on
select inst_id,fairness_down_converts,fairness_clears,light_works from gv$cr_block_server order by inst_id;
set heading off
select '----gv$bh----' from dual;
set heading on
select inst_id,file#,block#,status from gv$bh where file#=6 and block#=231 and status!='free';
set heading off
select '----x$bh----' from dual;
set heading on
col object_name format a20
set linesize 80
select inst_id,dbarfil,dbablk,CR_SCN_BAS,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') state_name,tch from x$bh where dbarfil=6 and dbablk=231 and state!=0;
///
// 场景1:_fairness_threshold=2(默认值)
///
session说明:其中session 1 node X是真正参与测试的session,session 2 node X是专用来观察相关视图内容,获取测试相关信息的session
---session 1 node 1:修改其中一条记录后commit;
alter system set optimizer_dynamic_sampling=0 scope=memory;
select * from scott.testfn_0730;
ID COL2
---------- ----
1 A
2 B
select distinct dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) blkno from scott.testfn_0730;
FNO BLKNO
---------- ----------
6 231
update scott.testfn_0730 set col2='a' where id=1;
commit;
---session 2 node 1: 查询_fairness_threshold参数值,记录buffer cache里block的状态,DOWN_CONVERTS次数,light_works次数
col ksppinm format a30
col ksppstvl format a20
col ksppdesc format a60
col ksppstcmnt format a20
set linesize 200
select x.inst_id,ksppinm,ksppity,ksppstvl,ksppdesc from x$ksppi x, x$ksppcv y where (x.indx = y.indx) and ksppinm in ('_fairness_threshold');
INST_ID KSPPINM KSPPITY KSPPSTVL KSPPDESC
---------- ------------------------------ ---------- -------------------- ------------------------------------------------------------
1 _fairness_threshold 3 2 number of times to CR serve before downgrading lock
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 4 0 0 <---node 1初始down_converts次数为4
2 4 0 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 xcur <---session 1 node 1 update之后在buffer cache里留下了xcur、cr两个block,其中cr是block修改前的映像,xcur是当前最新的block映像
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
1 6 231 0 xcur
1 6 231 1276027 cr <---1276027是cr生成时的scn
---session 1 node 2:第一次访问testfn_0730表
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数,light_works次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 4 0 0 <---down_converts次数未发生变化
2 4 0 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 xcur
1 6 231 cr
2 6 231 cr <---node 2 buffer cache新增一类型为cr的block,正是由node 1以其xcur型block为基础构造出来传输至node 2的
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
2 6 231 1276334 cr <---node 2上cr block scn=1276334代表了其从xcur构造而来那一刻的系统scn号
---session 2 node 1: data block dump on node 1
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_16988.trc
alter system dump datafile 6 block 231; <---dump block的内容,仅取出与GC有关的部分
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9b978):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: X rls: 0x0 acq: 0x0 latch: 6 <--- node1:lock: X 表示block上有Exclusive锁
flags: 0x20 fair: 1 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xadf5d770,0xadf5d770]
seq: 11 hist: 113 424 180 58 145:0 118 66 144:0 192 352 32
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02200000 state: XCURRENT tsn: 6 tsh: 2
addr: 0xadf5d638 obj: 15930 cls: DATA bscn: 0x0.13787d
。。。省略部分内容
---session 2 node 2: data block dump on node 2
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_18928.trc
alter system dump datafile 6 block 231; <---dump block的内容
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9df78):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: C rls: 0x0 acq: 0x0 latch: 6 <--- node2:lock: C 其中的C代表Consistent,表示这个block是处于consistent read目的而生成的,其不能被服用,所以block上的锁类型为KJUSERNL,KJUSERNL是一个placeholder类型的锁
flags: 0x21 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0x8af7e248,0xadffd5a8]
seq: 6 hist: 329 144:6 14 7 352 32
。。。省略部分内容
---session 1 node 2:第二次访问testfn_0730表
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 4 0 0
2 4 0 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 xcur
1 6 231 cr
2 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
2 6 231 1276334 cr
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 5 0 0 <---node 1的down convert次数从4增加到了5,发生了一次锁降级转换
2 4 0 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 scur <---node 1的xcur降级成了scur
1 6 231 cr
2 6 231 cr
2 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
2 6 231 1277433 cr <---node 2上新增了一个SCN=1277433的cr,这个cr是在node 1上的xcur降级成scur之前构造出来的
2 6 231 1276334 cr <---这是第一次select后生成的cr
---session 2 node 1: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 6 0 0 <---node 1的down convert次数从5增加到了6,不清楚这次锁降级转换是由哪个block触发的,但可以肯定与scott.testfn_0730表无关
2 22 1 0 <---node 2 down convert次数也从之前的4上升到22,也与scott.testfn_0730表无关,这里我们不必关注
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 scur
1 6 231 cr
2 6 231 cr
2 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
1 6 231 0 scur
1 6 231 1276027 cr
---session 2 node 1: data block dump on node 1
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_19706.trc
alter system dump datafile 6 block 231; <---dump block的内容,仅选取与GC有关的部分
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9b978):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: S rls: 0x0 acq: 0x0 latch: 6 <---block dump结果容易看出node 1对block 6/231持有的锁已从lock : X降级为lock : S
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xadf5d770,0xadf5d770]
seq: 14 hist: 45 4 54 113 424 180 58 145:0 118 66 144:0 192 352 32
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02200000 state: SCURRENT tsn: 6 tsh: 2
addr: 0xadf5d638 obj: 15930 cls: DATA bscn: 0x0.13787d
。。。省略部分内容
---session 2 node 2: data block dump on node 2
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_20858.trc
alter system dump datafile 6 block 231; <---dump block的内容
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9df78):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: C rls: 0x0 acq: 0x0 latch: 6 <---node 2还是保持为lock: C,即KJUSERNL锁
flags: 0x21 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0x8af954c8,0xadffd5a8]
seq: 11 hist: 329 144:6 14 7 352 329 144:6 14 7 352 32
。。。省略部分内容
---session 1 node 2:第三次访问testfn_0730表,发现多出了类型为scur的buffer
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 7 0 0 <---比上一次增加了1
2 27 1 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 scur <---node 2新生成出了一个scur,这个scur是从node 1传输过来的(node 1上的scur刚从xcur降级而来),scur表示该block在内存中的内容与磁盘上的内容一致
2 6 231 cr
2 6 231 cr
1 6 231 scur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
2 6 231 0 scur
2 6 231 1277433 cr
2 6 231 1276334 cr
---session 2 node 1: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 7 0 0
2 27 1 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 scur
2 6 231 cr
2 6 231 cr
1 6 231 scur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME
---------- ---------- ---------- ---------- ----------
1 6 231 0 scur
1 6 231 1276027 cr
---session 2 node 1: data block dump on node 1
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_21738.trc
alter system dump datafile 6 block 231; <---dump block的内容,仅显示与GC有关的部分
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9b978):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: S rls: 0x0 acq: 0x0 latch: 6 <---node1对block的锁维持lock: S
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xadf5d770,0xadf5d770]
seq: 16 hist: 227 160 45 4 54 113 424 180 58 145:0 118 66 144:0 192
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02200000 lflg: 0x2 state: SCURRENT tsn: 6 tsh: 1
addr: 0xadf5d638 obj: 15930 cls: DATA bscn: 0x0.13787d
。。。省略部分内容
---session 2 node 2: data block dump on node 2
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_22849.trc
alter system dump datafile 6 block 231; <---dump block的内容
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x89f9df78):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: S rls: 0x0 acq: 0x0 latch: 6 <---node 2上持有的锁从lock: C变为了lock: S,因为node 2有了自己的scur block
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xabf5f310,0xabf5f310]
seq: 16 hist: 227 144:0 213 7 352 329 144:6 14 7 352 329
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x08080000 state: SCURRENT tsn: 6 tsh: 1
addr: 0xabf5f1d8 obj: 15930 cls: DATA bscn: 0x0.13787d
。。。省略部分内容
---session 1 node 2:第四次访问testfn_0730表,从第四次开始往后每次都是访问scur这个buffer
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
SQL> @rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 37 2 1
2 40 1 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 scur
1 6 231 cr
2 6 231 scur
2 6 231 cr
2 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 0 scur 3 <---scur的访问次数一直在增加
2 6 231 1277433 cr 1
2 6 231 1276334 cr 1
---session 3 node 2:node 2上新开一个session访问testfn_0730表,发现也都是访问scur这个buffer,此时已不需要从远程实例cache里进行传输
select * from scott.testfn_0730;
SQL> @rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 44 2 1
2 40 1 0
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 scur <---node 1、node 2的buffer数量没有再增加
1 6 231 cr
2 6 231 scur
2 6 231 cr
2 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 0 scur 4 <---tch数量的不断上升表明node 2对block 6/231的访问最后都落到了scur block上
2 6 231 1277433 cr 1
2 6 231 1276334 cr 1
小结一下:
_fairness_threshold=2时,当node 2第2次访问node 1 buffer cache里的block时,buffer cache里该block的类型从xcur转换成scur,v$cr_block_server.FAIRNESS_DOWN_CONVERTS计数器加1;node 1持有的锁从Exclusive转换为Share,node 2持有的锁仍然是KJUSERNL;尽管如此,node 1仍然会构造出一个cr block传送给node 2,我们能在node 2的buffer cache里看到这个cr block;node 2第3次访问block时,node 2 buffer cache里才会新增一个从node 1传输而来的scur block,并且持有锁的类型也从KJUSERNL变为了Share。如果block内容一直不被更改,从_fairness_threshold+2轮查询开始node 2可在其本地的buffer cache里直接访问到该scur类型的block,不必从远程的node 1节点获得
下面看看_fairness_threshold=3的时候,是否遵循上述规律
///////
// 场景2:修改_fairness_threshold=3
///////
session说明:其中session 1 node X是真正参与测试的session,session 2 node X是专用来观察相关视图内容,获取测试相关信息的session
---session 1 node 1:修改其中一条记录后commit;
alter system set optimizer_dynamic_sampling=0 scope=memory;
select * from scott.testfn_0730;
ID COL2
---------- ----
1 A
2 B
select distinct dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) blkno from scott.testfn_0730;
FNO BLKNO
---------- ----------
6 231
update scott.testfn_0730 set col2='a' where id=1;
commit;
---session 2 node 1: 查询_fairness_threshold参数值,记录buffer cache里block的状态,DOWN_CONVERTS次数,light_works次数
col ksppinm format a30
col ksppstvl format a20
col ksppdesc format a60
col ksppstcmnt format a20
set linesize 200
select x.inst_id,ksppinm,ksppity,ksppstvl,ksppdesc from x$ksppi x, x$ksppcv y where (x.indx = y.indx) and ksppinm in ('_fairness_threshold');
INST_ID KSPPINM KSPPITY KSPPSTVL KSPPDESC
---------- ------------------------------ ---------- -------------------- ------------------------------------------------------------
1 _fairness_threshold 3 3 number of times to CR serve before downgrading lock
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 28 4 0
2 53 1 8
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 231 xcur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
1 6 231 0 xcur 2
1 6 231 1800959 cr 2
---session 1 node 2:第一次访问testfn_0730表
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数,light_works次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 29 4 0
2 53 1 8
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 cr <---node 2第一次访问的是一个cr类型的block由node1构造后传输而来
1 6 231 xcur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 1800996 cr 1
---session 1 node 2:第二次访问testfn_0730表
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 41 4 0
2 53 1 8
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 cr <---node 2第二次访问后在buffer cache里有了第二个cr类型的block
2 6 231 cr
1 6 231 xcur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 1801011 cr 1 <---CR_SCN_BAS=1801011对应的cr block是第二次查询所构造出的CR
2 6 231 1800996 cr 1 <---CR_SCN_BAS=1800996对应的cr block是第一次查询所构造出的CR
---session 1 node 2:第三次访问testfn_0730表
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 42 4 0 <---因为达到了_fairness_threshold所指定的阀值触发了down convert动作,所以FAIRNESS_DOWN_CONVERTS较上次查询的41增加了1
2 53 1 8
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 cr
2 6 231 cr
2 6 231 cr
1 6 231 scur <---node 1 buffer cache中的xcur转换成了scur
1 6 231 cr
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 1801037 cr 1 <---第三次查询构造出的cr
2 6 231 1801011 cr 1
2 6 231 1800996 cr 1
---session 2 node 1: data block dump on node 1
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_11782.trc
alter system dump datafile 6 block 231; <---dump block的内容,仅取出与GC有关的部分
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x8cfd7568):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: SG rls: 0x0 acq: 0x0 latch: 6 <---lock:SG 表示node 1上已经降级成了Share锁,G是global的意思
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.1ac5e4 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xabf051b0,0xabf051b0]
seq: 13 hist: 170 1 4 54 58 145:0 28 340 239 144:0 7 352 32
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02000001 state: SCURRENT tsn: 6 tsh: 2
addr: 0xabf05078 obj: 15930 cls: DATA bscn: 0x0.1b7b02 piscn: 0x0.1b7b4d
。。。省略部分内容
---session 2 node 2: data block dump on node 2
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_10722.trc
alter system dump datafile 6 block 231; <---dump block的内容
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x8aff9088):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: C rls: 0x0 acq: 0x0 latch: 6 <---lock:C 表示node 2持有的还是KJUSERNL类型的锁
flags: 0x21 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xb833b270,0x8afc13c8]
seq: 22 hist: 329 144:6 14 7 144:5 192 352 329 144:6 14 7
。。。省略部分内容
---session 1 node 2:第四次访问testfn_0730表
select * from scott.testfn_0730;
ID COL2
---------- ----
1 a
2 B
---session 2 node 2: 记录buffer cache里block的状态,DOWN_CONVERTS次数
@rec.sql
----gv$cr_block_server----
INST_ID FAIRNESS_DOWN_CONVERTS FAIRNESS_CLEARS LIGHT_WORKS
---------- ---------------------- --------------- -----------
1 46 4 0
2 53 1 8
----gv$bh----
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 231 scur <---第四轮查询过后node 2上不再生成新的cr,取而代之的是node 1传输过来的scur
2 6 231 cr
2 6 231 cr
2 6 231 cr
1 6 231 scur
1 6 231 cr
6 rows selected.
----x$bh----
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 231 0 scur 1
2 6 231 1801037 cr 1
2 6 231 1801011 cr 1
2 6 231 1800996 cr 1
---session 2 node 1: data block dump on node 1
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_10588.trc
alter system dump datafile 6 block 231; <---dump block的内容,仅选取与GC有关的部分
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x8cfd7568):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: SG rls: 0x0 acq: 0x0 latch: 6 <---lock:SG node 1上仍然维持Share锁
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.1ac5e4 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xabf051b0,0xabf051b0]
seq: 20 hist: 225 212 424 72 257 59 227 170 1 4 54 58 145:0 28 340
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x02200000 state: SCURRENT tsn: 6 tsh: 2
addr: 0xabf05078 obj: 15930 cls: DATA bscn: 0x0.1b7b02
。。。省略部分内容
---session 2 node 2: data block dump on node 2
select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_11315.trc
alter system dump datafile 6 block 231; <---dump block的内容
。。。省略部分内容
GLOBAL CACHE ELEMENT DUMP (address: 0x8aff9088):
id1: 0xe7 id2: 0x6 pkey: OBJ#15930 block: (6/231)
lock: S rls: 0x0 acq: 0x0 latch: 6 <---lock:SG node 2从KJUSERNL类的锁转换成Share锁
flags: 0x20 fair: 0 recovery: 0 fpin: 'kdswh11: kdst_fetch'
bscn: 0x0.0 bctx: (nil) write: 0 scan: 0x0
lcp: (nil) lnk: [NULL] lch: [0xabeefc70,0xabeefc70]
seq: 29 hist: 227 144:0 213 7 144:5 192 352 329 144:6 14 7
LIST OF BUFFERS LINKED TO THIS GLOBAL CACHE ELEMENT:
flg: 0x08080000 state: SCURRENT tsn: 6 tsh: 1
addr: 0xabeefb38 obj: 15930 cls: DATA bscn: 0x0.1b7b02
。。。省略部分内容
小结一下:
_fairness_threshold=3时,当node 2第3次访问node 1 buffer cache里的block时,node 1 buffer cache里该block的类型从xcur转换成scur,v$cr_block_server.FAIRNESS_DOWN_CONVERTS计数器加1;node 1持有的锁从Exclusive转换为Share,node 2持有的锁仍然是KJUSERNL;此时,node 1仍然会构造出一个cr block传送给node 2,我们能在node 2的buffer cache里看到这个cr block;node 2第4次访问block时,node 2 buffer cache里才会新增一个从node 1传输而来的scur block,并且持有锁的类型也从KJUSERNL变为了Share。如果block内容一直不被更改,从_fairness_threshold+2轮查询开始node 2可在其本地的buffer cache里直接访问到该scur类型的block,不必从远程的node 1节点获得
总结:
_fairness_threshold的可以看出oracle研发过程中的精雕细琢,为了在锁转换产生的开销与cr block构造产生的开销之间找到平衡,提供_fairness_threshold参数的同时给了用户一个灵活调节的手段,细节决定成败,Oracle RAC无愧为业界优秀的数据库集群软件
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/53956/viewspace-2124241/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/53956/viewspace-2124241/