陈老师:1415968548 郑老师:2735197625 乐老师:354331153
客服热线:
19941464235 / 19906632509 / 19906733890 / 19905812933(微信同号)

客服微信

【Oracle OCP】11g-latch:cache buffer chains的研究及模拟

作者:炎燚小寶
发布时间:2023-12-19 09:31
浏览量:587

本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。


一、实验逻辑读申请的latch:cache buffer chains次数

1、创建测试表及索引

--创建用户
create user apps identified by oracle;
grant connect,resource to apps;
alter user apps quota unlimited on users;
--创建表
drop table apps.t1;
create table apps.t1(id int,name varchar2(10));
insert into apps.t1 values(1,'AAA');
commit;
--创建唯一索引
create unique index apps.idx_t1_id on apps.t1(id);
--创建普通索引
create index apps.idx_t1_id1 on apps.t1(id,0);


2.获取apps.t1表的第一行文件号、块号

 select rowid,
       dbms_rowid.rowid_relative_fno(rowid) file#, 
       dbms_rowid.rowid_block_number(rowid) block#,
       id,
       name
  from apps.t1
 where rownum = 1; 

ROWID                   FILE#     BLOCK#         ID NAME
------------------ ---------- ---------- ---------- ----------
AAAVW2AAEAAAACsAAA          4        172          1 AAA


3.根据 DBA获取 CBC Latch 的地址

SQL> select hladdr from x$bh where file#=4 and dbablk=172;
HLADDR
----------------
00000000F11CF178


4.根据CBC Latch的地址可以查出这个 CBC Latch 被获得的次数

set linesize 1000
col name for a30
select addr,name,gets from v$latch_children  where addr='00000000F11CF178';
ADDR             NAME                                 GETS
---------------- ------------------------------ ----------
00000000F11CF178 cache buffers chains                16379


5.再次读取apps.t1表的第一行数据

SQL> select id,name from apps.t1 where rowid='AAAVW2AAEAAAACsAAA';
执行计划如下
Execution Plan
----------------------------------------------------------
Plan hash value: 487051824
-----------------------------------------------------------------------------------
| Id  | Operation                  | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |      |     1 |    32 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY USER ROWID| T1   |     1 |    32 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------


6.开启新的会话,查询apps.t1表的第一行,观察select被堵

SQL> select addr,name,gets from v$latch_children  where addr='00000000E3FB87E8';
ADDR             NAME                                 GETS
---------------- ------------------------------ ----------
00000000E3FB87E8 cache buffers chains                  287

这里说明,通过ROWID访问数据的方式,一次逻辑读要加两次 CBC Latch,一次为了加 Buffer Pin,一次为了释放 Buffer Pin!


提问:索引唯一扫描,索引范围扫描和全表扫描,分别需要几次latch

这里简单总结一下测试结果

访问方式 访问表块申请cbc latch的次数
TABLE ACCESS FULL 2
INDEX RANGE SCAN 2
INDEX UNIQUE SCAN 1
TABLE ACCESS BY USER ROWID 2


二、使用 oradebug 跟踪 CBC Latch 等待事件


1、开启一个新的会话

SQL> oradebug setmypid
Statement processed.
SQL> oradebug peek 0x00000000F11CF178 4     
 -- 观察 CBC Latch 地址为 0x1D1C266D8 开始之后的4字节信息的值为0
[1D1C266D8, 1D1C266DC) = 00000000
SQL> oradebug poke 0x00000000F11CF178 4 1   
--修改 CBC Latch 地址为 0x1D1C266D8 开始的4字节信息的值为1,相当于获取了 Latch
BEFORE: [1D1C266D8, 1D1C266DC) = 00000000 
--修改前的值
AFTER: [1D1C266D8, 1D1C266DC) = 00000001  
 --修改后的值


2. 再开一个新的会话执行select,未观察到阻塞

SQL> conn / as sysdba
Connected.
SQL> select sid from v$mystat where rownum=1;
       SID
----------
       768
SQL> select id,name from apps.t1 where rowid='AAAVW2AAEAAAACsAAA';

        ID NAME
---------- ----------
         1 AAA


3.新开一个会话,执行update

SQL> select sid from v$mystat where rownum=1;
       SID
----------
       771
SQL> update apps.t1 set id=2 where rowid='AAAVW2AAEAAAACsAAA';
。。。。hang死


4、查看当前等待

SQL> set line 200 pagesize 9999 
SQL> col event for a50 
SQL> Select inst_id,event,count(*) from gv$session where status='ACTIVE' and wait_class#<> 6 group by inst_id,event order by 1;

   INST_ID EVENT                                                COUNT(*)
---------- -------------------------------------------------- ----------
         1 SQL*Net message to client                                   1
         1 latch: cache buffers chains                                 1

--查看等待的会话
SQL> select sid from gv$session where event='latch: cache buffers chains';

       SID
----------
        768  -->这是执行update的会话


6、新会话再次执行select,发现被阻塞

SQL>  select id,name from apps.t1 where rowid='AAAVW2AAEAAAACsAAA';
。。。。hang死

--查看等待情况
SQL> Select inst_id,event,count(*) from gv$session where status='ACTIVE' and wait_class#<> 6 group by inst_id,event order by 1;

   INST_ID EVENT                                                COUNT(*)
---------- -------------------------------------------------- ----------
         1 SQL*Net message to client                                   1
         1 latch: cache buffers chains                                 2


7、释放 lacth

SQL> oradebug poke 0x00000000F11CF178 4 0


总结:

1、在通过poke持有表块对应的cbc latch时,通过select不会造成阻塞,update时会产生阻塞

2、因为update需要申请X模式的cbc latch,导致后面的select申请不到S模式的cbc latch,进一步被阻塞



思考:select一定不会产生cbc latch吗?可以通过以下实验验证

1、环境准备
create table apps.cbc_test(id number,name varchar2(200)) tablespace apps;
insert into apps.cbc_test select rownum,object_name from sys.dba_objects;
commit;


2、创建存储过程,查询表
create or replace procedure cbc_do_select_idx_range is
begin
  for x in (select /*+ index(a,idx_cbc_id)*/ * from apps.cbc_test a where id>0)loop
    null;
  end loop; 
end;
/
说明:可以通过HINT来控制SQL的执行计划,观察执行计划走索引唯一扫描,索引范围扫描,全表扫描的时候,会不会产生cbc latch竞争。

3、创建并发JOB来执行查询
var job_no number;
begin
 for idx in 1 .. 200 loop
   dbms_job.submit(:job_no,'cbc_do_select_idx_range;');
   commit;
 end loop; 
end;
/

4、查看数据库的等待
SQL> set line 200 pagesize 9999 
SQL> col event for a50 
SQL> Select inst_id,event,count(*) from gv$session where status='ACTIVE' and wait_class#<> 6 group by inst_id,event order by 1;