如果用过RAC那么你一定见到过这些等待事件:gc buffer busy acquire/release、gc cr/current block 2-way、gc cr/current block busy ..... 不一一列举了。对于这些事件的具体含义网上资料不少,因此不作深入介绍,本文关注的是这类等待事件在何种情况下会出现,设计了部分场景尽可能的模拟出这些等待
#########要用到的脚本清单
~~~~~~~~~~~~~~~~~
sess_1st.sql
~~~~~~~~~~~~~~~~~
define v_inst1=&1
define v_inst2=&3
define v_sid1=&2
define v_sid2=&4
drop table sess_evt_1st;
create table sess_evt_1st as select inst_id,sid,event,total_waits from gv$session_event where (inst_id=&v_inst1 and sid in (&v_sid1)) or (inst_id=&v_inst2 and sid in (&v_sid2)) order by inst_id,sid,event;
~~~~~~~~~~~~~~~~~
sess_2nd.sql
~~~~~~~~~~~~~~~~~
define v_inst1=&1;
define v_sid1=&2;
declare
v_count_1st number;
begin
select count(1) into v_count_1st from sess_evt_1st;
if (v_count_1st < 1)
then
insert into sess_evt_1st select * from sess_evt_2nd;
commit;
end if;
end;
/
truncate table sess_evt_2nd;
insert into sess_evt_2nd select inst_id,sid,event,total_waits from gv$session_event where inst_id=&v_inst1 and sid in (&v_sid1) and wait_class!='Idle' order by inst_id,sid,event;
commit;
col event format a30
set linesize 120 pagesize 60
select nd.sid,nd.event,nd.total_waits-nvl(st.total_waits,0) diff_waits from sess_evt_1st st,sess_evt_2nd nd where st.inst_id(+)=nd.inst_id and st.sid(+)=nd.sid
and st.event(+)=nd.event order by event,sid;
truncate table sess_evt_1st;
~~~~~~~~~~~~~~~~~
sess_1st_4p.sql
~~~~~~~~~~~~~~~~~
define v_inst1=&1
define v_inst2=&3
define v_sid1=&2
define v_sid2=&4
drop table sess_evt_1st;
create table sess_evt_1st as select inst_id,sid,event,total_waits from gv$session_event where (inst_id=&v_inst1 and sid in (&v_sid1)) or (inst_id=&v_inst2 and
sid in (&v_sid2)) order by inst_id,sid,event;
~~~~~~~~~~~~~~~~~
sess_2nd_4p.sql
~~~~~~~~~~~~~~~~~
define v_inst1=&1
define v_inst2=&3
define v_sid1=&2
define v_sid2=&4
drop table sess_evt_2nd;
create table sess_evt_2nd as select inst_id,sid,event,total_waits from gv$session_event where (inst_id=&v_inst1 and sid in (&v_sid1)) or (inst_id=&v_inst2 and
sid in (&v_sid2)) order by inst_id,sid,event;
col event format a30
set linesize 120 pagesize 60
select nd.sid,nd.event,nd.total_waits-nvl(st.total_waits,0) diff_waits from sess_evt_1st st,sess_evt_2nd nd where st.inst_id(+)=nd.inst_id and st.sid(+)=nd.sid
and st.event(+)=nd.event order by event,sid;
~~~~~~~~~~~~~~~~~
query_xbh.sql
~~~~~~~~~~~~~~~~~
col object_name format a20
set heading off
set linesize 80
select '------x$bh------' from dual;
set heading on
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=&fileno and dbablk=&blkno) or (dbarfil=&ufileno and dbablk=&ublkno)) and state!=0;
~~~~~~~~~~~~~~~~~
query_vbh.sql
~~~~~~~~~~~~~~~~~
set heading off
select '------v$bh------' from dual;
set heading on
select inst_id,file#,block#,status from gv$bh where ((file#=&fileno and block#=&blkno) or (file#=&ufileno and block#=&ublkno)) and status!='free';
/
//gc cr disk read事件
/
事件描述:
当node 1需要读取的block在node 2的buffer cache里,且block中包含尚未提交的事务,那么node 2的LMS进程需要使用undo record将该block回滚至node 1发起那一时刻的内容后再传给node 1,假如这时undo record所在的undo block不在node 2的buffer cache里,node 1上就会出现gc cr disk read事件,表示node 1正等待node 2的LMS授予其直接从磁盘读取undo block的权限。
模拟事件产生:gc cr disk read
--session 1 node 1:update col2='A'的记录
select * from scott.t0820_1;
ID C
---------- -
7.68176826 A
2.14433612 B
select dbms_rowid.rowid_relative_fno(rowid) rfno,dbms_rowid.rowid_block_number(rowid) blkno from scott.t0820_1;
RFNO BLKNO
---------- ----------
6 253
6 253
update scott.t0820_1 set id=dbms_random.value(1,10) where col2='A';
--session 2 node 1: 记录一下session 1 node 1使用的undo block,查询v$bh、x$bh里与本次update有关的data block和undo block
select xidusn,ubafil,ubablk,used_ublk from v$transaction ;
XIDUSN UBAFIL UBABLK USED_UBLK
---------- ---------- ---------- ----------
7 3 7954 1
set heading on
define fileno=6
define blkno=253
define ufileno=3
define ublkno=7954
@query_xbh.sql
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
1 6 253 0 xcur 2
1 6 253 2759860 cr 2
1 3 7954 0 xcur 3
@query_vbh.sql
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
1 6 253 xcur
1 3 7954 xcur
1 6 253 cr
--session 1 node 2: 会话信息
select sid,serial# from v$session where sid=sys_context('userenv','sid');
SID SERIAL#
---------- ----------
14 9
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_30958.trc
--session 2 node 2:保存session 1 node 2执行select前的会话信息,开启10046 trace
@sess_1st.sql 2 14
exec dbms_monitor.session_trace_enable(14,9);
--session 1 node 2: select col2='B'的记录
select * from scott.t0820_1 where col2='B';
ID C
---------- -
2.14433612 B
--session 2 node 2:收集执行期间的wait events,结束跟踪
@sess_2nd.sql 2 14
SID EVENT DIFF_WAITS
---------- ------------------------------ ----------
14 Disk file operations I/O 1
14 SQL*Net message to client 2
14 events in waitclass Other 0
14 gc cr multi block request 1
14 gc current block 2-way 2
14 library cache lock 0
14 library cache pin 0
14 row cache lock 16
exec dbms_monitor.session_trace_disable(14,9);
--session 2 node 2:查询v$bh、x$bh找到与Scott.t0820_1表及undo有关的block
define fileno=6
define blkno=253
define ufileno=3
define ublkno=7954
@query_xbh.sql
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
2 6 253 2760009 cr 1
@query_vbh.sql
INST_ID FILE# BLOCK# STATUS
---------- ---------- ---------- ----------
2 6 253 cr
1 6 253 xcur
1 3 7954 xcur
1 6 253 cr
1 6 253 cr
--session 2 node 1:查询x$bh与Scott.t0820_1表及undo有关的block
define fileno=6
define blkno=253
define ufileno=3
define ublkno=7954
@query_xbh.sql
INST_ID DBARFIL DBABLK CR_SCN_BAS STATE_NAME TCH
---------- ---------- ---------- ---------- ---------- ----------
1 6 253 2760009 cr 0 <---从CR_SCN_BAS可以看出这个cr与node 2上的cr是一个版本,TCH=0可以看出cr构造于node 1然后传输到node 2,在node 1上并没有被访问
1 6 253 0 xcur 2
1 6 253 2759860 cr 2
1 3 7954 0 xcur 4
生成的trace文件susedb12_ora_30958.trc里与scott.t0820_1表及undo有关的条目摘录如下:
WAIT #140341723483448: nam='gc current block 2-way' ela= 460 p1=6 p2=250 p3=4 obj#=15976 tim=1474008654658633
。。。省略了部分内容
WAIT #140341723483448: nam='gc cr multi block request' ela= 2505 file#=6 block#=253 class#=1 obj#=15976 tim=1474008654665173
FETCH #140341723483448:c=0,e=3294,p=0,cr=5,cu=0,mis=0,r=1,dep=0,og=1,plh=168131571,tim=1474008654665281
这其中6/253是我们所操作的数据块本身,6/250是scott.t0820_1的segment header
col owner format a13
col segment_name format a25
col header_file format 999
col header_block format 999
set linesize 100
select owner,segment_name,header_file,header_block from dba_segments where segment_name='T0820_1';
OWNER SEGMENT_NAME HEADER_FILE HEADER_BLOCK
------------- ------------------------- ----------- ------------
SCOTT T0820_1 6 250
6/250引发了gc current block 2-way,因为node 2从未访问过segment_header,所以node 2必须从node 1得到最新的segment header信息;6/253引发了gc cr multi block request,因为node 1 update之后没有commit,所以node 2发起的select是一次Consistent read从node 1的buffer cache将6/253读到local buffer cache
---session 1 node 2: flush buffer cache
alter system flush buffer_cache;
define fileno=6
define blkno=253
define ufileno=3
define ublkno=7954
@query_xbh.sql
no rows selected
@query_vbh.sql
no rows selected
---session 2 node 1: 虽然是在node 2上执行的flush操作,node 1本地的buffer cache里也找不到这些buffer了
define fileno=6
define blkno=253
define ufileno=3
define ublkno=7954
@query_xbh.sql
no rows selected
@query_vbh.sql
no rows selected
---session 1 node 2: 获取diag file name
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_30958.trc
--session 2 node 2:保存session 1 node 2执行select前的会话信息,开启10046 trace
@sess_1st.sql 2 14
exec dbms_monitor.session_trace_enable(14,9);
--session 1 node 2: 再一次select col2='B'的记录
select * from scott.t0820_1 where col2='B';
ID C
---------- -
2.14433612 B
--session 2 node 2:收集执行期间的wait events,结束跟踪
@sess_2nd.sql 2 14
SID EVENT DIFF_WAITS
---------- ------------------------------ ----------
14 Disk file operations I/O 3
14 SQL*Net message to client 2
14 db file scattered read 1 <---6/251~6/255
14 db file sequential read 2 <---6/250、3/7954
14 events in waitclass Other 1
14 gc cr block 2-way 1 <---3/224
14 gc cr disk read 1 <---3/7954
14 gc cr multi block request 0
14 gc current block 2-way 0
14 library cache lock 0
14 library cache pin 0
14 os thread startup 1
14 row cache lock 2
exec dbms_monitor.session_trace_disable(14,9);
trace文件susedb12_ora_30958.trc里的相关条目按顺序摘录如下:
WAIT #140341723494584: nam='db file sequential read' ela= 621 file#=6 block#=250 blocks=1 obj#=15976 tim=1474009210968492
WAIT #140341723494584: nam='db file scattered read' ela= 14721 file#=6 block#=251 blocks=5 obj#=15976 tim=1474009210984834
WAIT #140341723494584: nam='gc cr block 2-way' ela= 1900 p1=3 p2=224 p3=29 obj#=0 tim=1474009210988479
WAIT #140341723494584: nam='gc cr disk read' ela= 1547 p1=3 p2=7954 p3=30 obj#=0 tim=1474009210991241
WAIT #140341723494584: nam='db file sequential read' ela= 19524 file#=3 block#=7954 blocks=1 obj#=0 tim=1474009211100974
db file sequential read:6/250,segment header,单块从磁盘读取
db file scattered read:file#=6 block#=251 blocks=5表示从6/251开始的连续5个block通过multi block read方式一次性从磁盘读取
gc cr block 2-way:3/224是undo header,从node 1的buffer cache里一致读访问这个block,我们通过dba_rollback_segs与v$transaction关联得到undo header block:
select segment_id,file_id,block_id from dba_rollback_segs,v$transaction where segment_id=xidusn;
SEGMENT_ID FILE_ID BLOCK_ID
---------- ---------- ----------
7 3 224 <---7号undo segment 的header存在于block 3/224
上面的等待事件验证了node 2一致读的过程:读到6/253时发现包含未提交的事务,要先访问undo header(访问期间产生了gc cr block 2-way事件),以从其事务槽里获取包含6/253修改前映像的undo block,然后再对undo block进行访问,因undo block已被刷出node 1的buffer cache,gc cr disk read表示node 2获得node 1 LMS进程的准许从磁盘读取node 1的undo block 3/7954,下一个db file sequential read等待事件就是完成从磁盘上读取3/7954这个动作,最后利用undo block里的undo record构造出select发起时刻的一致性结果数据返回node 1
/
//gc current/cr block 2-way
/
事件描述:
gc current block 2-way
node 1、node 2的buffer cache里都没有block A,这时node 1读取了某个block A里的某一行,随后node 2也读取了block A或者对block A里的某一行作了DML操作,这两种情况下node 2上都会出现"gc current block 2-way"等待,current在这里表示node 2读取或修改的block版本是最新的,该block里不存在未提交的事务。值得注意的是在"gc current block 2-way"事件发生之后,GRD里会为该block上KJUSERPR(读操作)或者KJUSEREX锁(写操作)
gc cr block 2-way
细分一下有两种情况
(1)、node 1修改了记录但没有提交:
node 1、node 2的buffer cache里都没有block A,这时node 1修改了block A里的某一行,但没有提交;随后node 2执行了Select block A操作,按照一致性读的定义,node 2此时应该收到block A在select发起那一时刻所对应的快照block A',block A'将由node 1上的LMS进程以应用undo record到block A的方式构造出来后传给node 2,此时在node 2上就发生了一次"gc cr block 2-way"等待事件,node 2接收到的block A'在buffer cache中标记为cr类型,cr类的block仅满足当次查询的需要,无法被之后的查询所重用,也就是说假如node 2仅接着又发起一次对于block A的select操作,node 1上的LMS进程还是会重新构造出一个block A''后传递给node 2,尽管block A''与block A'的内容是完全一样的。这一特性决定了cr block在构造及传输的过程中在GRD里不需要任何的锁来保护。
2、node 1修改了记录且已经提交:
node 1、node 2的buffer cache里都没有block A,这时node 1修改了block A里的某一行,并且已经提交。因为_fairness_threshold参数的作用,当node 2执行了Select block A操作,仍然有可能触发node 1上的LMS进程构造cr block然后传输给node 2的动作,node 2就会遇到gc cr block 2-way等待。关于_fairness_threshold参数的详细介绍可参考我的另一篇文章"探究隐含参数_fairness_threshold"(http://blog.itpub.net/53956/viewspace-2124241)
模拟事件的产生:gc current block 2-way
前提:scott.tst0625_1表不存在于任何节点的buffer cache里
--session 1 node 1:每个block仅有一行数据,共20行,算上segment header载入buffer cache的block共有21个
set pagesize 30
select distinct dbms_rowid.rowid_relative_fno(rowid) rfno,dbms_rowid.rowid_block_number(rowid) from scott.tst0625_1 t order by 1,2;
RFNO DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
---------- ------------------------------------
6 131
6 132
6 133
6 134
6 135
6 136
6 137
6 138
6 139
6 140
6 141
6 142
6 143
6 145
6 146
6 147
6 148
6 149
6 150
6 151
select count(*) from scott.tst0625_1;
COUNT(*)
----------
20
set pagesize 100
select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15698 and status!='free' order by inst_id,block#;
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 130 scur 15698 <---是segment header
1 6 131 scur 15698
1 6 132 scur 15698
1 6 133 scur 15698
1 6 134 scur 15698
1 6 135 scur 15698
1 6 136 scur 15698
1 6 137 scur 15698
1 6 138 scur 15698
1 6 139 scur 15698
1 6 140 scur 15698
1 6 141 scur 15698
1 6 142 scur 15698
1 6 143 scur 15698
1 6 145 scur 15698
1 6 146 scur 15698
1 6 147 scur 15698
1 6 148 scur 15698
1 6 149 scur 15698
1 6 150 scur 15698
1 6 151 scur 15698
--session 1 node 2:获取会话信息
select sid,serial# from v$session where sid=sys_context('userenv','sid');
SID SERIAL#
---------- ----------
14 11
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_5935.trc
--session 2 node 2:保存会话的初始waitevent,开启10046 trace
@sess_1st.sql 2 14
exec dbms_monitor.session_trace_enable(14,11);
--session 1 node 2:select指定rowid访问特定行
select id,length(N1),length(N2) from scott.tst0625_1 where rowid in ('AAAD1SAAGAAAACDAAA','AAAD1SAAGAAAACEAAA');
ID LENGTH(N1) LENGTH(N2)
---------- ---------- ----------
1 3000 3200
3 3000 3200
--session 2 node 2
@sess_2nd.sql 2 14
SID EVENT DIFF_WAITS
---------- ------------------------------ ----------
14 Disk file operations I/O 1
14 SQL*Net message to client 2
14 db file parallel read 0
14 db file scattered read 0
14 db file sequential read 0
14 events in waitclass Other 0
14 gc cr grant 2-way 0
14 gc cr grant congested 0
14 gc cr multi block request 0
14 gc current block 2-way 2 <---两次gc current block 2-way,每次对应一个block
14 library cache lock 0
14 library cache pin 0
14 row cache lock 4
exec dbms_monitor.session_trace_disable(14,11);
select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15698 and status!='free' order by inst_id,block#;
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 130 scur 15698
1 6 131 scur 15698
1 6 132 scur 15698
1 6 133 scur 15698
1 6 134 scur 15698
1 6 135 scur 15698
1 6 136 scur 15698
1 6 137 scur 15698
1 6 138 scur 15698
1 6 139 scur 15698
1 6 140 scur 15698
1 6 141 scur 15698
1 6 142 scur 15698
1 6 143 scur 15698
1 6 145 scur 15698
1 6 146 scur 15698
1 6 147 scur 15698
1 6 148 scur 15698
1 6 149 scur 15698
1 6 150 scur 15698
1 6 151 scur 15698
2 6 131 scur 15698 <---dbms_rowid.rowid_block_number('AAAD1SAAGAAAACDAAA')=131
2 6 132 scur 15698 <---dbms_rowid.rowid_block_number('AAAD1SAAGAAAACEAAA')=132
Trace文件susedb12_ora_5935.trc里的内容可以看出两次gc current block 2-way等待分别来自6/131、6/132,红色部分;用了两次逻辑读每次返回一行
PARSING IN CURSOR #140532781792704 len=111 dep=0 uid=0 oct=3 lid=0 tim=1474026770006054 hv=1561302837 ad='88d4bb28' sqlid='50mu165fhz5tp'
select id,length(N1),length(N2) from scott.tst0625_1 where rowid in ('AAAD1SAAGAAAACDAAA','AAAD1SAAGAAAACEAAA')
END OF STMT
PARSE #140532781792704:c=4001,e=10969,p=0,cr=13,cu=0,mis=1,r=0,dep=0,og=1,plh=950802872,tim=1474026770006050
EXEC #140532781792704:c=0,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=950802872,tim=1474026770006141
WAIT #140532781792704: nam='SQL*Net message to client' ela= 4 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1474026770006175
WAIT #140532781792704: nam='Disk file operations I/O' ela= 5 FileOperation=2 fileno=6 filetype=2 obj#=-1 tim=1474026770006284
*** 2016-09-16 19:52:50.008
WAIT #140532781792704: nam='gc current block 2-way' ela= 1581 p1=6 p2=131 p3=1 obj#=15698 tim=1474026770007998
FETCH #140532781792704:c=0,e=1993,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=950802872,tim=1474026770008190
WAIT #140532781792704: nam='SQL*Net message from client' ela= 167 driver id=1650815232 #bytes=1 p3=0 obj#=15698 tim=1474026770008416
WAIT #140532781792704: nam='gc current block 2-way' ela= 856 p1=6 p2=132 p3=1 obj#=15698 tim=1474026770009429
WAIT #140532781792704: nam='SQL*Net message to client' ela= 4 driver id=1650815232 #bytes=1 p3=0 obj#=15698 tim=1474026770009543
FETCH #140532781792704:c=0,e=1119,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=950802872,tim=1474026770009568
STAT #140532781792704 id=1 cnt=2 pid=0 pos=1 obj=0 op='INLIST ITERATOR (cr=2 pr=0 pw=0 time=1960 us)'
STAT #140532781792704 id=2 cnt=2 pid=1 pos=1 obj=15698 op='TABLE ACCESS BY USER ROWID TST0625_1 (cr=2 pr=0 pw=0 time=2978 us cost=1 size=3129 card=1)'
因为所有block在node 1 buffer cache里的类型都是scur,即shared current,表示block的当前最新版本,所以node 2访问6/131、6/132两个block是产生的等待事件是gc current block 2-way,而不是gc cr block 2-way
上例使用了rowid in ... 作为条件,仅为能够比较清晰的看清gc current block 2-way的本质,在实际应用中很少使用rowid作为条件,用的更多的是
select id,length(N1),length(N2) from scott.tst0625_1 where id in (1,3)这种可读性更为强的写法,我们来看下,以"id in (1,3)"为条件的情况下是否还会出现gc current block 2-way事件
--session 1 node 1:每个block仅有一行数据,共20行,算上segment header,载入buffer cache的block共有21个
alter system flush buffer_cache;
select count(*) from scott.tst0625_1;
COUNT(*)
----------
20
select id,length(N1),length(N2),dbms_rowid.rowid_block_number(rowid) from scott.tst0625_1;
ID LENGTH(N1) LENGTH(N2) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
---------- ---------- ---------- ------------------------------------
1 3000 3200 131
3 3000 3200 132
4 3000 3200 133
5 3000 3200 134
2 3000 3200 135
11 3000 3200 136
12 3000 3200 137
13 3000 3200 138
6 3000 3200 139
7 3000 3200 140
8 3000 3200 141
9 3000 3200 142
10 3000 3200 143
14 3000 3200 145
16 3000 3200 146
17 3000 3200 147
18 3000 3200 148
19 3000 3200 149
20 3000 3200 150
15 3000 3200 151
set pagesize 100
select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15698 and status!='free' order by inst_id,block#;
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 130 scur 15698 <---segment header block
1 6 131 scur 15698
1 6 132 scur 15698
1 6 133 scur 15698
1 6 134 scur 15698
1 6 135 scur 15698
1 6 136 scur 15698
1 6 137 scur 15698
1 6 138 scur 15698
1 6 139 scur 15698
1 6 140 scur 15698
1 6 141 scur 15698
1 6 142 scur 15698
1 6 143 scur 15698
1 6 145 scur 15698
1 6 146 scur 15698
1 6 147 scur 15698
1 6 148 scur 15698
1 6 149 scur 15698
1 6 150 scur 15698
1 6 151 scur 15698
--session 1 node 2:获取会话信息
select sid,serial# from v$session where sid=sys_context('userenv','sid');
SID SERIAL#
---------- ----------
14 13
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_11146.trc
--session 2 node 2:保存会话的初始waitevent,开启10046 trace
@sess_1st.sql 2 14
exec dbms_monitor.session_trace_enable(14,13);
--session 1 node 2:select指定rowid访问特定行
select id,length(N1),length(N2) from scott.tst0625_1 where id in (1,2); <---id字段没有索引,因此会引起全表扫描,下面会观察到表中的所有block都load到了buffer cache
ID LENGTH(N1) LENGTH(N2)
---------- ---------- ----------
1 3000 3200
3 3000 3200
--session 2 node 2
@sess_2nd.sql 2 14
SID EVENT DIFF_WAITS
---------- ------------------------------ ----------
14 Disk file operations I/O 1
14 SQL*Net message to client 2
14 db file parallel read 0
14 db file scattered read 0
14 db file sequential read 0
14 events in waitclass Other 0
14 gc cr grant 2-way 0
14 gc cr grant congested 0
14 gc cr multi block request 3
14 gc current block 2-way 2 <---其中只有一次来自于和tst0625_1表相关的block 6/130,6/130是segment header,trcfile的分析见下
14 row cache lock 3
exec dbms_monitor.session_trace_disable(14,13);
SQL> select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15698 and status!='free' order by inst_id,block#;
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 130 scur 15698
1 6 131 scur 15698
1 6 132 scur 15698
1 6 133 scur 15698
1 6 134 scur 15698
1 6 135 scur 15698
1 6 136 scur 15698
1 6 137 scur 15698
1 6 138 scur 15698
1 6 139 scur 15698
1 6 140 scur 15698
1 6 141 scur 15698
1 6 142 scur 15698
1 6 143 scur 15698
1 6 145 scur 15698
1 6 146 scur 15698
1 6 147 scur 15698
1 6 148 scur 15698
1 6 149 scur 15698
1 6 150 scur 15698
1 6 151 scur 15698
2 6 130 scur 15698
2 6 131 scur 15698
2 6 132 scur 15698
2 6 133 scur 15698
2 6 134 scur 15698
2 6 135 scur 15698
2 6 136 scur 15698
2 6 137 scur 15698
2 6 138 scur 15698
2 6 139 scur 15698
2 6 140 scur 15698
2 6 141 scur 15698
2 6 142 scur 15698
2 6 143 scur 15698
2 6 145 scur 15698
2 6 146 scur 15698
2 6 147 scur 15698
2 6 148 scur 15698
2 6 149 scur 15698
2 6 150 scur 15698
2 6 151 scur 15698
select segment_name,extent_id,file_id,block_id,blocks from dba_extents where segment_name='TST0625_1';
SEGMENT_NAME EXTENT_ID FILE_ID BLOCK_ID BLOCKS
------------------ ----------- ---------- ---------- ----------
TST0625_1 0 6 128 8
TST0625_1 1 6 136 8
TST0625_1 2 6 144 8
Trace文件susedb12_ora_11146.trc内容看到仅出现一次针对segment header block 6/130的gc current block 2-way等待事件,剩下三次都是gc cr multi block request
PARSING IN CURSOR #140600891635672 len=70 dep=0 uid=0 oct=3 lid=0 tim=1474029113549743 hv=2015775894 ad='88c94360' sqlid='1tvrcqtw2cm4q'
select id,length(N1),length(N2) from scott.tst0625_1 where id in (1,2)
END OF STMT
PARSE #140600891635672:c=8000,e=7666,p=0,cr=19,cu=0,mis=1,r=0,dep=0,og=1,plh=2149608728,tim=1474029113549738
EXEC #140600891635672:c=0,e=32,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2149608728,tim=1474029113549842
WAIT #140600891635672: nam='SQL*Net message to client' ela= 17 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1474029113549895
WAIT #140600891635672: nam='Disk file operations I/O' ela= 7 FileOperation=2 fileno=6 filetype=2 obj#=-1 tim=1474029113550070
WAIT #140600891635672: nam='gc current block 2-way' ela= 443 p1=6 p2=130 p3=4 obj#=15698 tim=1474029113550650
WAIT #140600891635672: nam='gc cr multi block request' ela= 1453 file#=6 block#=135 class#=1 obj#=15698 tim=1474029113552591
FETCH #140600891635672:c=0,e=2721,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,plh=2149608728,tim=1474029113552744
WAIT #140600891635672: nam='SQL*Net message from client' ela= 231 driver id=1650815232 #bytes=1 p3=0 obj#=15698 tim=1474029113553032
WAIT #140600891635672: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=15698 tim=1474029113553161
WAIT #140600891635672: nam='gc cr multi block request' ela= 1697 file#=6 block#=143 class#=1 obj#=15698 tim=1474029113555335
WAIT #140600891635672: nam='gc cr multi block request' ela= 1450 file#=6 block#=151 class#=1 obj#=15698 tim=1474029113557108
FETCH #140600891635672:c=4000,e=4093,p=0,cr=19,cu=0,mis=0,r=1,dep=0,og=1,plh=2149608728,tim=1474029113557166
STAT #140600891635672 id=1 cnt=2 pid=0 pos=1 obj=15698 op='TABLE ACCESS FULL TST0625_1 (cr=23 pr=0 pw=0 time=2662 us cost=7 size=49872 card=16)'
可以看到gc cr multi block request的三次等待都是以每个extent里的最后一个block_id作为标识,但这并不能说明有多少个extent就会触发多少次gc cr multi block request,后面会有详细说明
WAIT #140600891635672: nam='gc cr multi block request' ela= 1453 file#=6 block#=135 class#=1 obj#=15698 tim=1474029113552591
。。。
WAIT #140600891635672: nam='gc cr multi block request' ela= 1697 file#=6 block#=143 class#=1 obj#=15698 tim=1474029113555335
WAIT #140600891635672: nam='gc cr multi block request' ela= 1450 file#=6 block#=151 class#=1 obj#=15698 tim=1474029113557108
这三次gc cr multi block request产生了多少读,下面这行给出了说明:
FETCH #140600891635672:c=4000,e=4093,p=0,cr=19,cu=0,mis=0,r=1,dep=0,og=1,plh=2149608728,tim=1474029113557166
cr=19表示一致性读取了19个block,r=1表示返回1行,结合前面dba_extents和gv$bh的输出我们具体分析一下cr=19,r=1是如何得到的:
extent 0 范围:6/128~6/135,其中6/128~6/130分别是1st level BMB、2nd level BMB、Segment header,6/131~6/135是data block,包含segment header的extent比较特殊从第二个data block也就是6/132才开始记入gc cr multi block request,因此贡献了4次cr
extent 1 范围:6/136~6/143,都是data block,共8个,贡献了8次cr
extent 2 范围:6/144~6/151,6/144没有被读入buffer cache,剩下的6/145~6/151共7个是data block,贡献了7次cr
因此三次gc cr multi block request就产生了19次cr,因为在6/132~6/135、6/136~6/143、6/144~6/151这19个block里包含id=2的记录,所以r=1
Trace File里还有一行,cr=4,读取的这4个block范围就是6/128~6/131,其中仅6/131是Data block且包含id=1的记录,所以r=1
FETCH #140600891635672:c=0,e=2721,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,plh=2149608728,tim=1474029113552744
顺带提一下,在表没有索引的情况下gc cr multi block request等待次数和表里有多少个extent,也和db_file_multiblock_read_count的值有关,若db_file_multiblock_read_count < 单个extent里的block个数,那么访问一个extent就有可能产生多次gc cr multi block request等待,反之一个extent触发一次gc cr multi block request,有兴趣的童鞋可以自行验证一下
模拟事件产生:gc cr block 2-way
session 1 node 2 sid: 16
session 1 node 1 sid: 425
---session 1 node 1:
create table scott.tst0628_1(id number,n1 varchar2(3000),n2 varchar2(3200)) tablespace test1;
declare
begin
for i in 1..20 loop
insert into scott.tst0628_1 values(i,dbms_random.string('l',3000),dbms_random.string('l',3200));
end loop;
commit;
end;
/
set pagesize 100
select object_id from dba_objects where object_name='TST0628_1';
OBJECT_ID
----------
15781
select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15781 and status!='free' order by inst_id,block#;
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 152 xcur 15781
1 6 153 xcur 15781
1 6 154 xcur 15781
1 6 155 xcur 15781
1 6 156 xcur 15781
1 6 157 xcur 15781
1 6 158 xcur 15781
1 6 159 xcur 15781
1 6 160 xcur 15781
1 6 161 xcur 15781
1 6 162 xcur 15781
1 6 163 xcur 15781
1 6 164 xcur 15781
1 6 165 xcur 15781
1 6 166 xcur 15781
1 6 167 xcur 15781
1 6 168 xcur 15781
1 6 169 xcur 15781
1 6 170 xcur 15781
1 6 171 xcur 15781
1 6 172 xcur 15781
1 6 173 xcur 15781
1 6 174 xcur 15781
1 6 175 xcur 15781
select rowid from scott.tst0628_1;
ROWID
------------------
AAAD2lAAGAAAACbAAA
AAAD2lAAGAAAACcAAA
AAAD2lAAGAAAACdAAA
AAAD2lAAGAAAACeAAA
AAAD2lAAGAAAACfAAA
AAAD2lAAGAAAACgAAA
AAAD2lAAGAAAAChAAA
AAAD2lAAGAAAACiAAA
AAAD2lAAGAAAACjAAA
AAAD2lAAGAAAACkAAA
AAAD2lAAGAAAAClAAA
AAAD2lAAGAAAACmAAA
AAAD2lAAGAAAACnAAA
AAAD2lAAGAAAACpAAA
AAAD2lAAGAAAACqAAA
AAAD2lAAGAAAACrAAA
AAAD2lAAGAAAACsAAA
AAAD2lAAGAAAACtAAA
AAAD2lAAGAAAACuAAA
AAAD2lAAGAAAACvAAA
--session 1 node 2: 开启10046
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_7114.trc
alter session set optimizer_dynamic_sampling=0;
alter session set events '10046 trace name context forever,level 8';
--session 2 node 2 : 统计session 1 node 2 (sid=452)的初始等待事件值
@/home/oracle/sess_1st.sql 2 16
--session 1 node 2:
select * from scott.tst0628_1 where rowid in ('AAAD2lAAGAAAACbAAA','AAAD2lAAGAAAACcAAA');
--session 2 node 2: 统计出sid=452的最终等待事件次数
@/home/oracle/sess_2nd.sql 2 16
SID EVENT DIFF_WAITS
---------- ------------------------------ ----------
16 Disk file operations I/O 0
16 SQL*Net break/reset to client 2
16 SQL*Net message to client 12
16 SQL*Net more data to client 6
16 db file sequential read 0
16 events in waitclass Other 0
16 gc cr block 2-way 4 <--其中三次与scott.tst0628_1表里的块有关6/154(segment header)、6/155(AAAD2lAAGAAAACbAAA)、6/156(AAAD2lAAGAAAACcAAA),
16 gc cr grant 2-way 0
16 gc cr multi block request 0
16 gc current block 2-way 2 <--没有与scott.tst0628_1相关的表
16 gc current block congested 0
16 library cache lock 1
16 library cache pin 1
16 row cache lock 6
--session 1 node 2:关闭10046
alter session set events '10046 trace name context off';
观察TraceFile:susedb12_ora_7114.trc里能发现以下段落
WAIT #139749596070128: nam='gc cr block 2-way' ela= 716 p1=6 p2=154 p3=4 obj#=15781 tim=1467290171765964
WAIT #139749596070128: nam='gc cr block 2-way' ela= 611 p1=6 p2=155 p3=1 obj#=15781 tim=1467290171771829
WAIT #139749596070128: nam='gc cr block 2-way' ela= 811 p1=6 p2=156 p3=1 obj#=15781 tim=1467290171773509
set pagesize 100
select inst_id,file#,block#,STATUS,objd from gv$bh where objd=15781 and status!='free' order by inst_id,block#; <---注意这时的buffer类型
INST_ID FILE# BLOCK# STATUS OBJD
---------- ---------- ---------- ---------- ----------
1 6 152 xcur 15781
1 6 153 xcur 15781
1 6 154 scur 15781
1 6 155 scur 15781
1 6 156 scur 15781
1 6 157 xcur 15781
1 6 158 xcur 15781
1 6 159 xcur 15781
1 6 160 xcur 15781
1 6 161 xcur 15781
1 6 162 xcur 15781
1 6 163 xcur 15781
1 6 164 xcur 15781
1 6 165 xcur 15781
1 6 166 xcur 15781
1 6 167 xcur 15781
1 6 168 xcur 15781
1 6 169 xcur 15781
1 6 170 xcur 15781
1 6 171 xcur 15781
1 6 172 xcur 15781
1 6 173 xcur 15781
1 6 174 xcur 15781
1 6 175 xcur 15781
2 6 154 cr 15781 <---6/154 新增类型为cr的buffer,segment header
2 6 155 cr 15781 <---6/155 新增类型为cr的buffer
2 6 156 cr 15781 <---6/156 新增类型为cr的buffer
可以看到虽然node 1在往tst0628_1表insert了记录且已经提交,但node 2 读到的还是cr 类型的block,所以触发的是"gc cr block 2-way"
值得一提的是不管是gc cr block 2-way还是gc current block 2-way,它们的出现并不意味着RAC的性能出现了问题,可以认为这是消息类的等待事件,仅仅表示两节点间存在block的传输,但如果在AWR里发现这两种等待事件平均耗时较长(>10ms),就可以认为网络上存在瓶颈,需要联系网络管理员介入处理
//gc cr/current block busy事件
事件描述:
gc current block busy
node 1正在更新block A的时候node 2也发起了对block A的更新,这时node 2在等待接收node 1上的LMS进程构造出block A在node 2发起更新时刻的block映像,node 2在接收到block A映像之前,就会处于gc current block busy状态
gc cr block busy
当node 1正在更新block A的时候,node 2发起了对block A的查询,这时node 2在等待接收node 1上的LMS进程构造出block A在node 2发起查询时刻的block映像,node 2在接收到block A映像之前,就会处于gc cr block busy状态
模拟gc current block busy、gc cr block busy:
---session 1 node 1
select id,col2,dbms_rowid.rowid_block_number(rowid) from scott.t0820_1;
ID C DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
---------- - ------------------------------------
2.28795961 A 253
2.35719885 B 253
select sid,serial# from v$session where sid=sys_context('userenv','sid');
SID SERIAL#
---------- ----------
17 57
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb11/trace/susedb11_ora_18905.trc
---session 1 node 2
select sid,serial# from v$session where sid=sys_context('userenv','sid');
SID SERIAL#
---------- ----------
17 81
select value from v$diag_info where name='Default Trace File';
/oracle/app/oracle/diag/rdbms/susedb1/susedb12/trace/susedb12_ora_15878.trc
---session 2 node 1
@sess_1st_4p.sql 1 17 2 17
exec dbms_monitor.session_trace_enable(17,57);
---session 2 node 2
exec dbms_monitor.session_trace_enable(17,81);
---session 1 node 1
set timing on
declare
i number:=0;
begin
while ( i < 10000 )
loop
update scott.t0820_1 set id=dbms_random.value(0,10) where col2='A';
commit;
i:=i+1;
end loop;
end;
/
---session 1 node 2
set timing on
declare
i number:=0;
begin
while ( i < 10000 )
loop
update scott.t0820_1 set id=dbms_random.value(0,10) where col2='B';
commit;
i:=i+1;
end loop;
end;
/
---session 2 node 1
@sess_2nd_4p.sql 1 17 2 17
INST_ID SID EVENT DIFF_WAITS
---------- ---------- ------------------------------ ----------
1 17 Disk file operations I/O 2
2 17 Disk file operations I/O 3
1 17 SQL*Net break/reset to client 0
1 17 SQL*Net message from client 5
2 17 SQL*Net message from client 5
1 17 SQL*Net message to client 5
2 17 SQL*Net message to client 5
2 17 enq: TM - contention 1
1 17 events in waitclass Other 2
2 17 events in waitclass Other 9
1 17 gc buffer busy release 4522
2 17 gc buffer busy release 2932
1 17 gc cr block 2-way 2748
2 17 gc cr block 2-way 3179
1 17 gc cr block busy 144
2 17 gc cr block busy 1045
1 17 gc cr block congested 58
2 17 gc cr block congested 56
1 17 gc cr failure 2
2 17 gc cr multi block request 1
1 17 gc current block 2-way 9
2 17 gc current block 2-way 42
1 17 gc current block busy 4680
2 17 gc current block busy 4686
1 17 gc current block congested 1
2 17 gc current block congested 1
1 17 latch: cache buffers chains 60
2 17 latch: cache buffers chains 110
2 17 latch: shared pool 1
1 17 library cache lock 0
2 17 library cache lock 1
1 17 library cache pin 0
2 17 library cache pin 1
1 17 log file sync 1
2 17 log file sync 1
2 17 resmgr:cpu quantum 1
2 17 row cache lock 193
exec dbms_monitor.session_trace_disable(17,57);
---session 2 node 2
exec dbms_monitor.session_trace_disable(17,81);
node 1、node 2的trcfile内容比较相似,仅摘录了node 1的trcfile:susedb11_ora_18905的片段进行分析:
没有gc等待的trace采样:
EXEC #139646861365968:c=0,e=78,p=0,cr=0,cu=1,mis=0,r=0,dep=1,og=0,plh=0,tim=1474783113862791
CLOSE #139646861365968:c=0,e=4,dep=1,type=3,tim=1474783113862842
EXEC #139646864444920:c=0,e=425,p=0,cr=7,cu=3,mis=0,r=1,dep=1,og=1,plh=2096051787,tim=1474783113863291
CLOSE #139646864444920:c=0,e=73,dep=1,type=3,tim=1474783113863529
XCTEND rlbk=0, rd_only=0, tim=1474783113863573
有gc等待的trace采样片段1
EXEC #139646861365968:c=0,e=196,p=0,cr=0,cu=1,mis=0,r=0,dep=1,og=0,plh=0,tim=1474783114286635
CLOSE #139646861365968:c=0,e=7,dep=1,type=3,tim=1474783114286722
WAIT #139646864444920: nam='gc cr block 2-way' ela= 444 p1=4 p2=208 p3=47 obj#=0 tim=1474783114287931
WAIT #139646864444920: nam='gc buffer busy release' ela= 439 file#=6 block#=253 class#=1 obj#=15976 tim=1474783114288553
WAIT #139646864444920: nam='gc current block busy' ela= 34279 p1=6 p2=253 p3=33554433 obj#=15976 tim=1474783114322972
WAIT #139646864444920: nam='gc buffer busy release' ela= 1727 file#=6 block#=253 class#=1 obj#=15976 tim=1474783114325229
WAIT #139646864444920: nam='gc current block busy' ela= 2608 p1=6 p2=253 p3=33554433 obj#=15976 tim=1474783114328053
EXEC #139646864444920:c=4000,e=41550,p=0,cr=9,cu=3,mis=0,r=1,dep=1,og=1,plh=2096051787,tim=1474783114328300
CLOSE #139646864444920:c=0,e=5,dep=1,type=3,tim=1474783114328438
XCTEND rlbk=0, rd_only=0, tim=1474783114328560
有gc等待的trace采样片段2
EXEC #139646861365968:c=0,e=525,p=0,cr=0,cu=1,mis=0,r=0,dep=1,og=0,plh=0,tim=1474783114628065
CLOSE #139646861365968:c=0,e=15,dep=1,type=3,tim=1474783114628356
WAIT #139646864444920: nam='gc cr block 2-way' ela= 16928 p1=4 p2=272 p3=55 obj#=0 tim=1474783114646861
WAIT #139646864444920: nam='gc cr block busy' ela= 10248 p1=4 p2=12133 p3=56 obj#=0 tim=1474783114657967
WAIT #139646864444920: nam='gc current block busy' ela= 14530 p1=6 p2=253 p3=33554433 obj#=15976 tim=1474783114674653
WAIT #139646864444920: nam='gc buffer busy release' ela= 6202 file#=6 block#=253 class#=1 obj#=15976 tim=1474783114683424
WAIT #139646864444920: nam='gc current block busy' ela= 17825 p1=6 p2=253 p3=33554433 obj#=15976 tim=1474783114701812
EXEC #139646864444920:c=8000,e=74095,p=0,cr=9,cu=3,mis=0,r=1,dep=1,og=1,plh=2096051787,tim=1474783114702583
CLOSE #139646864444920:c=0,e=20,dep=1,type=3,tim=1474783114703614
XCTEND rlbk=0, rd_only=0, tim=1474783114703784
等待事件次数统计里以gc current block busy、gc cr block busy、gc cr block 2-way、gc buffer busy release四类事件居多
(1) gc current block busy
该事件集中发生在data block 6/253上,node 1、node 2同时在以很高的频率update block 6/253里的两条不同记录,当node 1 update时发现node 2已在GRD里给6/253上了独占锁,此时node 1就必须等待node 2上的LMS进程构造出6/253的映像,所以node 1会一直等在gc current block busy事件上直至接收到从node 2传过来的block映像
(2) gc cr block busy
node 1的144次gc cr block busy等待里,有128次发生在了undo segment header或者undo block上,在RAC的机制里为了防止远程节点的LMS过度忙于构造一致读的block,有时会将构造的工作交由请求节点的foreground process完成,具体来讲node 1因为一致读的需要其foreground process在构造6/253某一时刻映像的过程中需要读取node 2曾经使用过的undo segment header或者undo block,而恰好这时node 2也在更新同一个undo segment header或者undo block,node 1就有可能遇到gc cr block busy等待,v$cr_block_server.LIGHT_WORKS用来计数有多少次块构造是由foreground process来完成的;还有16次发生在了data block 6/253上,这种情形是由node 2的LMS进程而不是node 1的foreground process来构造一致读块。
(3) gc buffer busy release
集中发生在6/253这个block上。node 1尝试修改本地buffer cache中的block时,发现node 2已经在修改该block,并且该修改尚未完成,这时node 1就会出现gc buffer busy release等待。gc buffer busy release往往是被其它的等待事件触发的,比如gc cr block busy,其自身并非问题的根源
(4) gc cr block 2-way
集中发生在undo segment header或者undo block上,node 1上foreground process在构造6/253一致性读映像的过程中需要从node 2节点获取undo segment header里的事务槽信息,gc cr block 2-way仅表示本地与远程节点有过块传输,并不意味着实例间存在block的争用。