客服微信
本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。
--创建用户 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);
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
SQL> select hladdr from x$bh where file#=4 and dbablk=172; HLADDR ---------------- 00000000F11CF178
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
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 | -----------------------------------------------------------------------------------
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 |
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 --修改后的值
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
SQL> select sid from v$mystat where rownum=1; SID ---------- 771 SQL> update apps.t1 set id=2 where rowid='AAAVW2AAEAAAACsAAA'; 。。。。hang死
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的会话
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
SQL> oradebug poke 0x00000000F11CF178 4 0
总结:
1、在通过poke持有表块对应的cbc latch时,通过select不会造成阻塞,update时会产生阻塞
2、因为update需要申请X模式的cbc latch,导致后面的select申请不到S模式的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;