使用了索引就一定能避免cache buffers chains争用吗

访问buffer cache里的数据块时需要先以独占模式申请管理hash bucket的latch,这个latch的名称就是所谓的cache buffers chains,系统中出现latch:cache buffers chains争用往往意味着以下两种可能:
1、多个会话并发访问相同的数据块(这是最常见的一种情况)
2、不同的数据块挂载在同一个hash bucket下,或者虽然挂载在不同的hash bucket下但这些hash bucket恰好受同一个cache buffer chains latch管理(一个latch可以管理多个hash bucket)

以上只是概念上的笼统描述,是否真会引起latch:cache buffers chains等待还与SQL语句的访问路径有关:Full Table Scan的访问路径下确实同上面所描述的,
但在用到索引的情况下是否会触发latch:cache buffers chains取决于以下5种因素:
1、如果是针对于唯一性索引的叶块的等值访问,这里包括仅访问唯一性索引本身和既访问唯一性索引又通过唯一性索引访问数据表两种情况,访问时都会以共享模式申请管理hash bucket的latch,所以即便多个会话并发访问buffer cache里的同一个唯一性索引的块,也不会出现latch:cache buffers chains等待事件,这时能观察到的等待事件一般是"cursor: pin S"

2、如果是针对于唯一性索引的叶块的非等值访问,当然也包含仅访问索引和既访问索引又访问数据表两种情况,访问时都会以独占模式申请管理hash bucket的latch,多个会话并发访问buffer cache里的同一个唯一性索引的块,会出现latch:cache buffers chains等待事件

3、对于非唯一性索引的叶块,和表里的数据块一样会以独占模式申请cache buffers chains latch

4、对于唯一性索引里的同一个索引块如果两个session同时以等值方式访问不会出现latch:cache buffers chains等待

5、对于唯一性索引里的同一个索引块如果分别被两个session以等值、非等值方式访问时会出现latch:cache buffers chains等待

6、没有索引
这里之所以强调叶块,是因为索引里的非叶块访问时都是以共享方式持有cache buffers chains latch的,对于唯一性和非唯一性索引均是如此


以下我们构造几个测试场景了解一下Oracle是如何管理cache buffers chains latch的:其中1~3测试在不同block被同一个latch管理的场景下进行;4~5测试在同一个block被多个session并发访问的场景下进行


#####场景1:一个非唯一性索引的数据块、一个表的数据块被不同的session访问引起latch: cache buffers chains争用
---创建表和索引
create table scott.t1119_cb1 tablespace ts1116 as select * from all_users;
create index scott.ind_t1119_cb1 on scott.t1119_cb1(user_id) tablespace ts1116 ;


---执行计划用到了索引
explain plan for select * from scott.t1119_cb1 where user_id=0;
set linesize 120 pagesize 100
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1836694578


---------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |     1 |    39 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1119_CB1     |     1 |    39 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND_T1119_CB1 |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------


---获取表、索引的object_id
select * from dba_objects where object_name in ('T1119_CB1','IND_T1119_CB1');
OWNER OBJECT_NAME SUBOBJECT_NAME OBJECT_ID
SCOTT IND_T1119_CB1 41332
SCOTT T1119_CB1 41331


set linesize 150
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41332;
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41332      82300 00000001109A5358 07000001BCD67618   35651584          0          9          1          5      60713 070000012ACE6000          1
     41332     156749 00000001109A5358 07000001BCE25910   35651584          0          1          1          5      60715 0700000123020000          5  <---index block
     41332     202672 00000001109A5358 07000001BCE98500   35651584          0          8          1          5      60712 070000014820E000          1
     41332     286932 00000001109A5358 07000001BCF567F8   35651584          0          4          1          5      60714 07000000F3F54000          4


SELECT * FROM SCOTT.T1119_CB1 where user_id=0;
SYS@tstdb1-SQL> select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41332;


       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41332      82300 00000001109A5358 07000001BCD67618   35651584          0          9          1          5      60713 070000012ACE6000          1
     41332     156750 00000001109A5358 07000001BCE25910   35651584          0          1          1          5      60715 0700000123020000          6  <---index block
     41332     202673 00000001109A5358 07000001BCE98500   35651584          0          8          1          5      60712 070000014820E000          1
     41332     286933 00000001109A5358 07000001BCF567F8   35651584          0          4          1          5      60714 07000000F3F54000          4


---由上述输出我们查看07000001BCE25910这个Latch下还包含哪些对象
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where hladdr='07000001BCE25910';
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
4294967295     156742 00000001109A5358 07000001BCE25910   35651584          0        102          1         10      12442 070000015C9C0000          1
4294967295     156743 00000001109A5210 07000001BCE25910          0          4         98          0         10      12442 0700000131352000          0
4294967295     156744 00000001109A50C8 07000001BCE25910          0          4         96          0         10      12442 07000001660F6000          0
     40172     156745 00000001109A5358 07000001BCE25910     524288          0          1          1          2      25634 070000011C380000          2
4294967295     156746 00000001109A5358 07000001BCE25910          0          4         96          0         10      43041 07000001593E6000          0
4294967295     156747 00000001109A5210 07000001BCE25910          0          4        102          0         10      43041 0700000182822000          0
     41332     156748 00000001109A5358 07000001BCE25910   35651584          0          1          1          5      60715 0700000123020000          6
     
---选取obj=40172对应的表SYS.WRH$_LATCH(注:obj=4294967295对应的block均来自于undo block,bitmap block等块,这些块不属于任何表或者索引),
col owner format a30
col object_name format a20
set linesize 120
select owner,object_name,data_object_id from dba_objects where data_object_id=40172;


OWNER                          OBJECT_NAME          DATA_OBJECT_ID
------------------------------ -------------------- --------------
SYS                            WRH$_LATCH                    40172


---构造出block 2/25634 第一行的rowid
select dbms_rowid.rowid_create(1,40172,2,25634,0) from dual;


DBMS_ROWID.ROWID_C
------------------
AAAJzsAACAAAGQiAAA


---开启session 1通过索引方式访问SCOTT.T1119_CB1表
declare
type typ1 is record (p1 varchar2(30),p2 number,p3 date); 
v_typ1 typ1;
begin
while ( true ) 
loop
select * into v_typ1 from scott.t1119_cb1 where user_id=0;
end loop;
end;
/


---接着开启session 2访问SYS.WRH$_LATCH表block 2/25634里的第一行
declare
type typ2 is record (p1 number,p2 number,p3 number); 
v_typ2 typ2;
begin
while ( true ) 
loop
select snap_id,dbid,instance_number into v_typ2 from sys.WRH$_LATCH where rowid='AAAJzsAACAAAGQiAAA';
end loop;
end;
/


---查询v$session可以看到有两个session都在等待"latch: cache buffers chains"事件
select sid,event,p1text,to_char(p1,'xxxxxxxx'),p2text,p2,p3text,p3 from v$session where event like 'latch%';
                 SID EVENT             P1TEXT            TO_CHAR(P1,'XXXX P2TEXT                              P2 P3TEXT                              P3
-------------------- ----------------- ----------------- ---------------- ----------------- -------------------- ----------------- --------------------
                 469 latch: cache buff address            7000001bce25910 number                             155 tries                                0
                     ers chains


                 995 latch: cache buff address            7000001bce25910 number                             155 tries                                0
                     ers chains


看出他们的P1值都为07000001BCE25910,表示他们都在争抢同一个catch buffers chains latch,


---根据P1、P2值到v$latch_children里匹配出该latch的访问统计,misses,大约占到了4%,另外还有sleeps
SYS@tstdb1-SQL> select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where latch#=155 and addr='07000001BCE25910';


ADDR                           LATCH#               CHILD# NAME                                      GETS               MISSES               SLEEPS            SPIN_GETS
---------------- -------------------- -------------------- ------------------------- -------------------- -------------------- -------------------- --------------------
07000001BCE25910                  155                16361 cache buffers chains                 212854610              9318472                  780              9317745


SYS@tstdb1-SQL> r
  1* select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where latch#=155 and addr='07000001BCE25910'


ADDR                           LATCH#               CHILD# NAME                                      GETS               MISSES               SLEEPS            SPIN_GETS
---------------- -------------------- -------------------- ------------------------- -------------------- -------------------- -------------------- --------------------
07000001BCE25910                  155                16361 cache buffers chains                 213145448              9329338                  781              9328610


#####场景2:两个同属于一个latch管理的唯一性索引块同时被以等值条件访问时,不会引起latch: cache buffers chains争用
---创建表和索引
create table scott.t1119_cb2 tablespace ts1116 as select * from all_users;
create unique index scott.ind_t1119_cb2 on scott.t1119_cb2(user_id) tablespace ts1116 ;


---执行计划用到了索引
explain plan for select * from scott.t1119_cb2 where user_id=0;
set linesize 120 pagesize 100
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1423192252


---------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |     1 |    39 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1119_CB2     |     1 |    39 |     1   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | IND_T1119_CB2 |     1 |       |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

---获取表、索引的object_id
select OWNER,OBJECT_NAME,OBJECT_ID,data_object_id from dba_objects where object_name in ('T1119_CB2','IND_T1119_CB2');
OWNER                          OBJECT_NAME           OBJECT_ID DATA_OBJECT_ID
------------------------------ -------------------- ---------- --------------
SCOTT                          IND_T1119_CB2             41334          41334
SCOTT                          T1119_CB2                 41333          41333


set linesize 150
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41334;
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41334      47225 0000000110B36A50 07000001B6B76538   33554433          0          9          1          5      60729 07000000F8434000          1
     41334     121764 0000000110B36A50 07000001BCDCA8D0   33554433          0          1          1          5      60731 0700000147812000          1   <---index block
     41334     167768 0000000110B36A50 07000001B6CA7420   33554433          0          8          1          5      60728 07000000FD0CC000          1
     41334     242213 0000000110B36A50 07000001BCEFB7B8   33554433          0          4          1          5      60730 07000001676C2000          1


select * from scott.t1119_cb2 where user_id=0;
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41334      47226 0000000110B36A50 07000001B6B76538   35651584          0          9          1          5      60729 07000000F8434000          1
     41334     121766 0000000110B36A50 07000001BCDCA8D0   35651584          0          1          1          5      60731 0700000147812000          2   <---index block
     41334     167772 0000000110B36A50 07000001B6CA7420   35651584          0          8          1          5      60728 07000000FD0CC000          1
     41334     242219 0000000110B36A50 07000001BCEFB7B8   35651584          0          4          1          5      60730 07000001676C2000          1


---由上述输出我们查看07000001BCE25910这个Latch下还包含哪些对象
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where hladdr='07000001BCDCA8D0';
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
4294967295     121764 0000000110A91130 07000001BCDCA8D0   35651584          0        102          1         10      12458 07000001651DE000          4
4294967295     121765 0000000110A90FE8 07000001BCDCA8D0          0          4         98          0         10      12458 0700000107ED0000          0
4294967295     121766 0000000110A90EA0 07000001BCDCA8D0          0          4         96          0         10      12458 07000001660E8000          0
     40166     121767 0000000110A91130 07000001BCDCA8D0     524288          0          1          1          2      25650 0700000110EB6000          2
4294967295     121768 0000000110A91130 07000001BCDCA8D0          0          4         96          0         10      43057 07000001593F2000          0
4294967295     121769 0000000110A90FE8 07000001BCDCA8D0          0          4        102          0         10      43057 0700000186482000          0
     41334     121770 0000000110A91130 07000001BCDCA8D0   35651584          0          1          1          5      60731 0700000147812000          2
     
---选取obj=40166对应的索引SYS.WRH$_SYSTEM_EVENT_PK(注:obj=4294967295对应的block均来自于undo block,bitmap block等块,这些块不属于任何表或者索引)
col owner format a30
col object_name format a20
set linesize 120
select owner,object_name,data_object_id from dba_objects where data_object_id=40166;
OWNER                          OBJECT_NAME          DATA_OBJECT_ID
------------------------------ -------------------- --------------
SYS                            WRH$_SYSTEM_EVENT_PK          40166


col column_name format a30
set linesize 100
select index_owner,table_name,index_name,column_name from dba_ind_columns where index_name='WRH$_SYSTEM_EVENT_PK';


INDEX_OWNER                    TABLE_NAME                     INDEX_NAME                     COLUMN_NAME
------------------------------ ------------------------------ ------------------------------ ------------------------------
SYS                            WRH$_SYSTEM_EVENT              WRH$_SYSTEM_EVENT_PK           DBID
SYS                            WRH$_SYSTEM_EVENT              WRH$_SYSTEM_EVENT_PK           SNAP_ID
SYS                            WRH$_SYSTEM_EVENT              WRH$_SYSTEM_EVENT_PK           INSTANCE_NUMBER
SYS                            WRH$_SYSTEM_EVENT              WRH$_SYSTEM_EVENT_PK           EVENT_ID


---对索引块2/25650做dump后截取了如下片段
Leaf block dump
===============
header address 4572180580=0x11085f064
kdxcolev 0                               <---表明是leaf block
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 2
kdxconro 258
kdxcofbo 552=0x228
kdxcofeo 562=0x232
kdxcoavs 10
kdxlespl 0
kdxlende 0
kdxlenxt 8414260=0x806434
kdxleprv 8414259=0x806433
kdxledsz 6
kdxlebksz 8032
row#0[562] flag: ------, lock: 0, len=29, data:(6):  00 80 6c da 00 29       <----0000000010|0000000110110011011010|0000000000101001=>file_id|blkno|row#=>2|27866|41,表示这条索引指向表中数据块的位置是block 2/27866里的第41行
col 0; len 6; (6):  c5 15 1f 42 30 4c
col 1; len 3; (3):  c2 29 29
col 2; len 2; (2):  c1 02
col 3; len 6; (6):  c5 11 2f 4f 09 53
row#1[591] flag: ------, lock: 0, len=29, data:(6):  00 80 6c da 00 2a
col 0; len 6; (6):  c5 15 1f 42 30 4c
col 1; len 3; (3):  c2 29 29
col 2; len 2; (2):  c1 02
col 3; len 6; (6):  c5 12 51 07 3d 0b


---找到数据块2/27866对应的表分区
select owner,segment_name,partition_name from dba_extents where file_id=2 and 27866 between block_id and block_id+blocks;


OWNER                          SEGMENT_NAME                                                                      PARTITION_NAME
------------------------------ --------------------------------------------------------------------------------- ------------------------------
SYS                            WRH$_SYSTEM_EVENT                                                                 WRH$_SYSTEM_2030654775_4012


col object_name format a30
set linesize 120
select data_object_id,object_name,subobject_name from dba_objects where object_name='WRH$_SYSTEM_EVENT' and subobject_name='WRH$_SYSTEM_2030654775_4012';
DATA_OBJECT_ID OBJECT_NAME                    SUBOBJECT_NAME
-------------- ------------------------------ ------------------------------
         40164 WRH$_SYSTEM_EVENT              WRH$_SYSTEM_2030654775_4012


---构造出block 2/27866第41行的rowid
select dbms_rowid.rowid_create(1,40164,2,27866,41) from dual;


DBMS_ROWID.ROWID_C
------------------
AAAJzkAACAAAGzaAAp


---找出这一行的数据
select DBID,SNAP_ID,INSTANCE_NUMBER,EVENT_ID from WRH$_SYSTEM_EVENT partition (WRH$_SYSTEM_2030654775_4012) where rowid='AAAJzkAACAAAGzaAAp';
      DBID    SNAP_ID INSTANCE_NUMBER   EVENT_ID
---------- ---------- --------------- ----------
2030654775       4040               1 1646780882


---根据索引的4个字段为条件进行查询两次
select DBID,SNAP_ID,INSTANCE_NUMBER,EVENT_ID from WRH$_SYSTEM_EVENT partition (WRH$_SYSTEM_2030654775_4012) where dbid=2030654775 and snap_id=4040 and instance_number=1 and event_id=1646780882;
      DBID    SNAP_ID INSTANCE_NUMBER   EVENT_ID
---------- ---------- --------------- ----------
2030654775       4040               1 1646780882


select DBID,SNAP_ID,INSTANCE_NUMBER,EVENT_ID from WRH$_SYSTEM_EVENT partition (WRH$_SYSTEM_2030654775_4012) where dbid=2030654775 and snap_id=4040 and instance_number=1 and event_id=1646780882;
      DBID    SNAP_ID INSTANCE_NUMBER   EVENT_ID
---------- ---------- --------------- ----------
2030654775       4040               1 1646780882


---查询后发现BA=07000000DDDCA000这行的TCH增加为2
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where hladdr='07000001BCDCA8D0'


       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
4294967295     132198 00000001109D91A0 07000001BCDCA8D0          0          4        102          0         10      12458 07000001651DE000          0
4294967295     132199 00000001109D9058 07000001BCDCA8D0          0          4         98          0         10      12458 0700000107ED0000          0
4294967295     132200 00000001109D8F10 07000001BCDCA8D0          0          4         96          0         10      12458 07000001660E8000          0
     40166     132201 00000001109D91A0 07000001BCDCA8D0          0          0          1          1          2      25650 07000000DDDCA000          2
     40166     132202 00000001109D9058 07000001BCDCA8D0          0          4          1          0          2      25650 0700000110EB6000          0
4294967295     132203 00000001109D91A0 07000001BCDCA8D0          0          4         96          0         10      43057 07000001593F2000          0
4294967295     132204 00000001109D9058 07000001BCDCA8D0          0          4        102          0         10      43057 0700000186482000          0
     41334     132205 00000001109D91A0 07000001BCDCA8D0          0          4          1          0          5      60731 0700000147812000          0
     
---至此同一个CBC latch控制下的两个block的访问语句都已经确定,我们在两个不同的session里执行下面两段代码,观察是否会发生latch: Cache buffers chains等待事件


***session 1运行:
declare
type rec_t1119 is record (p1 varchar2(30),p2 number,p3 date);
v_rec_t1119 rec_t1119;
begin
while ( true ) loop
select * into v_rec_t1119 from scott.t1119_cb2 where user_id=0;
end loop;
end;
/


***session 2运行:
declare
type rec_wrh is record (p1 number,p2 number,p3 number,p4 number);
v_rec_wrh rec_wrh;
begin
while ( true ) loop
select DBID,SNAP_ID,INSTANCE_NUMBER,EVENT_ID into v_rec_wrh from WRH$_SYSTEM_EVENT partition (WRH$_SYSTEM_2030654775_4012) where dbid=2030654775 and snap_id=4040 and instance_number=1 and event_id=1646780882; 
end loop;
end;
/


***session 3:期间没有观察到latch:cache buffer chains的等待,misses约占了2.8%,没有出现sleeps
SYS@tstdb1-SQL> select * from v$session where event like '%latch%';


no rows selected


SYS@tstdb1-SQL> select * from v$session where event like '%latch%'


no rows selected


SYS@tstdb1-SQL> select * from v$session where event like '%latch%';


no rows selected


SYS@tstdb1-SQL> select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where latch#=155 and addr='07000001BCDCA8D0';


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001BCDCA8D0        155      12705 cache buffers chains                                               37874388    1071789          0    1071789


正在执行的两个session一直处于空闲等待事件"SQL*Net message from client"
select sid,event from v$session where sid in (927,336)    <---正在执行的两个session id
       SID EVENT
---------- ----------------------------------------------------------------
       336 SQL*Net message from client
       927 SQL*Net message from client


结论2:以上测试证明同一个CBC Latch管理下的两个block如果都来自于唯一性索引,且访问形式都是等值访问,那么这两个块访问的时候不会引起latch:cache buffers chains等待


#####场景3:一个唯一性索引的数据块,一个表的数据块,在同一个latch管理的情况下,同时被访问(索引块使用等值访问)不会出现latch:cache buffers chains争用
create table scott.t1121_1 tablespace ts1116 as select * from all_users;
create unique index scott.uni_ind_uid on scott.t1121_1(user_id) tablespace ts1116;


col object_name format a30
col owner format a30
set linesize 150
select object_id,data_object_id,owner,object_name from dba_objects where object_name='UNI_IND_UID';
 OBJECT_ID DATA_OBJECT_ID OWNER                          OBJECT_NAME
---------- -------------- ------------------------------ ------------------------------
     41548          41548 SCOTT                          UNI_IND_UID


set linesize 150
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41548;


       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ---------- 
     41548        784 0000000111A29570 07000001B6AFE8D0          0          0          1          1          5      60763 0700000189C66000          0   <---index block
     41548       1471 0000000111A29570 07000001BCC9E678          0          0          8          1          5      60760 0700000189B7C000          0  
     41548       2547 0000000111A29570 07000001BCCA45C8          0          0          4          1          5      60762 070000018998A000          0
     41548       4346 0000000111A29570 07000001BCCADE20          0          0          9          1          5      60761 0700000189A86000          0




---查找同一CBC latch下的其它对象
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where hladdr='07000001B6AFE8D0';


       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
         2        839 0000000111A29570 07000001B6AFE8D0     524288          0          1          1          1      13134 0700000188834000          1
      6493        840 0000000111A29570 07000001B6AFE8D0          0          0          1          1          2      16540 07000001894A6000          0
       160        841 0000000111A29570 07000001B6AFE8D0     524288          0          1          1          1     105164 0700000189BB8000          1
        38        842 0000000111A29570 07000001B6AFE8D0          0          0          1          1          1        353 07000001881DE000          2
     41548        843 0000000111A29570 07000001B6AFE8D0          0          0          1          1          5      60763 0700000189C66000          0
       101        844 0000000111A29570 07000001B6AFE8D0     524288          0          1          1          1        819 0700000189A38000          2


---确定对象名、根据file_id/block_id构造出rowid
select object_id,data_object_id,owner,object_type,object_name from dba_objects where data_object_id=6493;
 OBJECT_ID DATA_OBJECT_ID OWNER                          OBJECT_TYPE         OBJECT_NAME
---------- -------------- ------------------------------ ------------------- ------------------------------
      6493           6493 SYS                            TABLE               WRH$_SYSMETRIC_SUMMARY


select dbms_rowid.rowid_create(1,6493,2,16540,0) from dual;
DBMS_ROWID.ROWID_C
------------------
AAABldAACAAAECcAAA


---事先验证一下两个block的访问语句一个是走unique index scan,另一个是走rowid直接访问
***scott.t1121_1表的访问语句
set linesize 120 pagesize 120
explain plan for select user_id from scott.t1121_1 where user_id=0;
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2735981831


---------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |     1 |    13 |     0   (0)| 00:00:01 |
|*  1 |  INDEX UNIQUE SCAN| UNI_IND_UID |     1 |    13 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------


***sys.WRH$_SYSMETRIC_SUMMARY表的访问语句是access by rowid
set linesize 120 pagesize 120
explain plan for select * from sys.WRH$_SYSMETRIC_SUMMARY where rowid='AAABldAACAAAECcAAA';
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2659935131


-----------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                        |     1 |    75 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY USER ROWID| WRH$_SYSMETRIC_SUMMARY |     1 |    75 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------


---开启两个session同时访问同一latch下的两个block,是否能观察到latch:cache buffers chains争用
***session 1:
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


***session 2:
declare
v_rec_wrh_sum number;
begin
while ( true ) loop
select average into v_rec_wrh_sum from sys.WRH$_SYSMETRIC_SUMMARY where rowid='AAABldAACAAAECcAAA';  
end loop;
end;
/


---观察session 1、session 2的等待事件,均为空闲等待,未观察到latch:cache buffer chains
SYS@tstdb1-SQL> select sid,event from v$session where sid in (467,532);


       SID EVENT
---------- ----------------------------------------------------------------
       467 SQL*Net message from client
       532 SQL*Net message from client


SYS@tstdb1-SQL> select sid,event from v$session where sid in (467,532)


       SID EVENT
---------- ----------------------------------------------------------------
       467 SQL*Net message from client
       532 SQL*Net message from client


---观察latch的统计信息,没有sleeps
SYS@tstdb1-SQL> select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where latch#=155 and addr='07000001B6AFE8D0'


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001B6AFE8D0        155        169 cache buffers chains                                               22062069     637837          0     637836


SYS@tstdb1-SQL> select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where latch#=155 and addr='07000001B6AFE8D0'


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001B6AFE8D0        155        169 cache buffers chains                                               22121216     639607          0     639606


结论3:如果同一个CBC latch下的两个block里只要有一个是unique index scan形式的等值访问,那么这两个block之间不会存在latch:cache buffers chains争用


上面的三个场景都是在不同的session访问两个不同的数据块时产生的,因为数据块所属的hash bucket受同一个cache buffers chains latch管理所致。
最后来看一下对于来自唯一性索引的同一个block如果以多个session并发访问,是否会出现等待


#####场景4:多个session并发以等值条件访问同一个唯一性索引块,不会出现latch:cache buffers chains争用
---还是延用之前的表scott.t1121_1及之上的唯一性索引作为例子
col owner format a30
col table_name format a40
set linesize 100
select owner,table_name from dba_tables where table_name='T1121_1';


OWNER                          TABLE_NAME
------------------------------ ----------------------------------------
SCOTT                          T1121_1


col object_name format a30
col owner format a30
set linesize 150
select object_id,data_object_id,owner,object_name from dba_objects where object_name='UNI_IND_UID';
 OBJECT_ID DATA_OBJECT_ID OWNER                          OBJECT_NAME
---------- -------------- ------------------------------ ------------------------------
     41548          41548 SCOTT                          UNI_IND_UID


set linesize 150
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41548;
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41548      13555 00000001109D7528 07000001B6AFE8D0          0          0          1          1          5      60763 0700000189C66000        176
     41548      25617 00000001109D7528 07000001BCC9E678          0          0          8          1          5      60760 0700000189B7C000          0
     41548      45048 00000001109D7528 07000001BCCA45C8          0          0          4          1          5      60762 070000018998A000          1
     41548      76570 00000001109D7528 07000001BCCADE20          0          0          9          1          5      60761 0700000189A86000          0


---session 1、session 2使用相同的语句
***session 1:
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


***session 2: 
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


---此时从v$session观察到关于这两个session的等待事件是"cursor: pin S"
select sid,event from v$session where sid in (467,266);
       SID EVENT
---------- ----------------------------------------------------------------
       266 cursor: pin S
       467 cursor: pin S


这里解释一下:因为sess 1和sess 2执行的语句完全相同所以在parse阶段就出现了关于library cache的严重竞争,所以大部分时间观察到的都是"cursor: pin S"这个等待事件


---为了避开"cursor: pin S"这个等待我们重新改写一下session 2里的sql语句加入一个无用的hint,重新测试一下
***session 1:
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


***session 2:
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select /*+ session_2 */ user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


---最终我们看到的是空闲等待,并没有latch:cache buffers chains等待
SYS@tstdb1-SQL> select sid,event from v$session where sid in (467,266);


       SID EVENT
---------- ----------------------------------------------------------------
       266 SQL*Net message from client
       467 SQL*Net message from client


SYS@tstdb1-SQL> select sid,event from v$session where sid in (467,266)


       SID EVENT
---------- ----------------------------------------------------------------
       266 SQL*Net message from client
       467 SQL*Net message from client


再扩展一下,如果select结果字段不含在唯一性索引里,即需要通过访问数据表来得到最终结果的,一样不会发生latch:cache buffers chains争用
set linesize 120 pagesize 100
explain plan for select username from scott.t1121_1 where user_id=0;  
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3873470818


-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |     1 |    12 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1121_1     |     1 |    12 |     1   (0)| 00:00:01 |    <--- rowid访问表
|*  2 |   INDEX UNIQUE SCAN         | UNI_IND_UID |     1 |       |     0   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------


***session 1:
declare
v_rec_t1121_1 varchar2(30);
begin
while ( true ) loop
select username into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


***session 2:
declare
v_rec_t1121_1 varchar2(30);
begin
while ( true ) loop
select /*+ session 2 */ username into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/


SYS@tstdb1-SQL> select sid,event from v$session where sid in (664,598);


       SID EVENT
---------- ----------------------------------------------------------------
       598 SQL*Net message from client
       664 SQL*Net message from client


SYS@tstdb1-SQL> select sid,event from v$session where sid in (664,598)


       SID EVENT
---------- ----------------------------------------------------------------
       598 SQL*Net message from client
       664 SQL*Net message from client


结论4:唯一性索引里的同一个block被不同的session同时以等值条��访问时,无论是仅访问索引本身还是也访问表,都不会存在latch:cache buffers chains争用

#####场景5:一个唯一性索引块被两个不同的session分别以等值与非等值方式访问时,能观察到latch:cache buffers chains争用
col owner format a30
col table_name format a40
set linesize 100
select owner,table_name from dba_tables where table_name='T1121_1';


OWNER                          TABLE_NAME
------------------------------ ----------------------------------------
SCOTT                          T1121_1


col object_name format a30
col owner format a30
set linesize 150
select object_id,data_object_id,owner,object_name from dba_objects where object_name='UNI_IND_UID';
 OBJECT_ID DATA_OBJECT_ID OWNER                          OBJECT_NAME
---------- -------------- ------------------------------ ------------------------------
     41548          41548 SCOTT                          UNI_IND_UID


set linesize 150
select obj,indx,addr,hladdr,flag,lru_flag,class,state,dbarfil,dbablk,ba,tch from x$bh where obj=41548;
       OBJ       INDX ADDR             HLADDR                 FLAG   LRU_FLAG      CLASS      STATE    DBARFIL     DBABLK BA                      TCH
---------- ---------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ----------
     41548       2804 0000000110994888 07000001B6AFE8D0          0          0          1          1          5      60763 070000018737A000        135
     41548       9178 0000000110994888 07000001BCCA45C8          0          0          4          1          5      60762 0700000181D54000          1


---确认非等值访问走的也是索引扫描
set linesize 120 pagesize 100
explain plan for select user_id from scott.t1121_1 where user_id<=10;
select * from table(dbms_xplan.display);


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2894018642


--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |     3 |    12 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| UNI_IND_UID |     3 |    12 |     1   (0)| 00:00:01 |
     
---session 1: 等值访问
declare
v_rec_t1121_1 number;
begin
while ( true ) loop
select user_id into v_rec_t1121_1 from scott.t1121_1 where user_id=0;  
end loop;
end;
/
     
---session 2: 非等值访问
DECLARE
TYPE t_t1121_user_id is table of scott.t1121_1.user_id%type;
v_t_1121_user_id t_t1121_user_id;
BEGIN
while ( true ) loop
select user_id bulk collect into v_t_1121_user_id from scott.t1121_1 where user_id<=10;
end loop;
END;
/


---观察两个session的等待事件:最终还是会观察到两个Session不断在等待latch: cache buffers chains事件
select sid,event,p1raw from v$session where sid in (401,266);


       SID EVENT                                                            P1RAW
---------- ---------------------------------------------------------------- ----------------
       266 latch: cache buffers chains                                      07000001B6AFE8D0
       401 latch: cache buffers chains                                      07000001B6AFE8D0


---latch统计信息变化:
SYS@tstdb1-SQL> r
  1* select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where addr='07000001B6AFE8D0'


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001B6AFE8D0        155        169 cache buffers chains                                              479766692   21527545        493   21527097


SYS@tstdb1-SQL> r
  1* select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where addr='07000001B6AFE8D0'


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001B6AFE8D0        155        169 cache buffers chains                                              479897592   21535649        494   21535200


SYS@tstdb1-SQL> r
  1* select addr,latch#,child#,name,gets,misses,sleeps,spin_gets from v$latch_children where addr='07000001B6AFE8D0'


ADDR                 LATCH#     CHILD# NAME                                                                   GETS     MISSES     SLEEPS  SPIN_GETS
---------------- ---------- ---------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------
07000001B6AFE8D0        155        169 cache buffers chains                                              480225332   21554044        495   21553594


结论5:当两个session分别以等值、非等值方式访问同一个唯一性索引块的时候,会出现cache buffers chains等待,因为非等值的session这时需要以独占方式持有CBC latch为的是修改指向索引块的Buffer header中的占位符,所以等值session访问buffer header时要等前面的独占模式结束后才能继续进行。反之非等值的session也要等待等值访问的session释放了以共享方式持有的CBC latch后才能以独占方式重新持有CBC latch并修改buffer header。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/aa3142dfd04faac362d14a4bbd2b3a51.html