思考: Oracle数据库中,select会被阻塞吗?写会阻塞读吗? 理论上,如果select时需要获取的Latch等锁资源无法立即获取到,就可能会出现等待,例如:
场景1:在Buffer Cache查找具体Buffer时,无法立即获取到CBC Latch资源,可能会出现等待。 场景2:SQL解析时,申请不到library cache lock、library cache pin等资源,可能会出现等待。
本文主要介绍场景1,并模拟update语句阻塞select的场景: 先看一下Oracle在Buffer Cache中如何找到需要的Buffer(逻辑读过程)?
1.进程根据要访问块的文件号、块号通过HASH算法计算出具体HASH值。 2.根据HASH值找到HASH Bucket。 3.搜索Bucket后的链表,查找对应的BH(Buffer Header)。 4.找到目标BH,从中取出Buffer的BA(Buffer Address)。 5.通过BA访问具体的Buffer.
由于SGA是公共内存,访问公共内存中任何数据都需要锁机制进行保护(Latch和Mutex)。 在上面的逻辑读过程中,搜索Bucket后的链表、访问BH中的BA,都需要Latch保护,这个Latch就是Cache Buffer Chain Lath(简称CBC Latch)。 那么如果select 执行时,申请不到Cache Buffer Chain Lath,select操作会被阻塞吗? 实验如下: 创建测试数据:
create table cjc.t1(id int,name varchar2(20)); create index cjc.i_t1_id on cjc.t1(id); insert into cjc.t1 values(1,'chen'); insert into cjc.t1 values(2,'ju'); insert into cjc.t1 values(3,'chao'); commit; select * from cjc.t1; ID NAME ---------- -------------------- 1 chen 2 ju 3 chao
查看数据rowid,文件号,块号等。
select rowid, dbms_rowid.rowid_relative_fno(rowid) file#, dbms_rowid.rowid_block_number(rowid) block#, id, name from cjc.t1; ROWID FILE# BLOCK# ID NAME ------------------ ---------- ---------- ---------- -------------------- AAAVVhAAFAAAACHAAA 5 135 1 chen AAAVVhAAFAAAACHAAB 5 135 2 ju AAAVVhAAFAAAACHAAC 5 135 3 chao
根据DBA获取CBC Latch 地址
SQL> select HLADDR from x$bh where file#=5 and DBABLK=135; HLADDR ---------------- 000000008022FE60 000000008022FE60
查询此Latch保护的Buffer
set line 100 col owner for a10 col object_name for a15 select file#,DBABLK,owner,object_name,object_type from x$bh a,dba_objects b where HLADDR='000000008022FE60' and a.obj=b.data_object_id; FILE# DBABLK OWNER OBJECT_NAME OBJECT_TYPE ---------- ---------- ---------- --------------- ------------------- 1 34695 SYS I_OBJ2 INDEX 1 52280 SYS OBJ$ TABLE 1 60956 SYS I_IDL_UB11 INDEX 1 4096 SYS TABSUBPART$ TABLE 2 3164 SYS WRI$_ADV_TASKS TABLE 5 135 CJC T1 TABLE 6 rows selected.
查询CBC Latch被获取的次数
col name for a20 select name,gets from v$latch_children where addr='000000008022FE60'; NAME GETS -------------------- ---------- cache buffers chains 452
读取第一行数据
select id,name from cjc.t1 where rowid='AAAVVhAAFAAAACHAAA'; ID NAME ---------- -------------------- 1 chen
再次查询,访问次数多了2次
SQL> select name,gets from v$latch_children where addr='000000008022FE60'; NAME GETS -------------------- ---------- cache buffers chains 454
执行awr快照
exec dbms_workload_repository.create_snapshot();
通过oradebug工具,模拟latch: cache buffers chains不释放
SQL> oradebug setmypid SQL> oradebug peek 0x000000008022FE60 4 [08022FE60, 08022FE64) = 00000000 锁定 SQL> oradebug poke 0x000000008022FE60 4 1 BEFORE: [08022FE60, 08022FE64) = 00000000 AFTER: [08022FE60, 08022FE64) = 00000001
会话40:可以正常查询
SQL> select distinct sid from v$mystat; SQL> select id,name from cjc.t1 where rowid='AAAVVhAAFAAAACHAAA'; ID NAME ---------- -------------------- 1 chen
会话31:无法对这条数据执行update,因为申请X模式的cbc latch时出现等待
SQL> select distinct sid from v$mystat; SQL> update cjc.t1 set id=100 where rowid='AAAVVhAAFAAAACHAAA'; 卡住
会话29:select查询出现了等待,因为update 需要申请X模式的cbc latch,导致后面的select 申请不到S模式的cbc latch进一步被阻塞。
SQL> select id,name from cjc.t1 where rowid='AAAVVhAAFAAAACHAAA'; 卡住
查询:
SQL> select * from dba_waiters; no rows selected
被阻塞的会话29和31等待事件都是 latch: cache buffers chains
set line 300 col username for a10 col event for a30 select SID,USERNAME,STATUS,event,P1RAW,P2RAW from v$session where username='CJC'; SID USERNAME STATUS EVENT P1RAW P2RAW ---------- ---------- -------- ------------------------------ ---------------- ---------------- 29 CJC ACTIVE latch: cache buffers chains 000000008022FE60 00000000000000B1 31 CJC ACTIVE latch: cache buffers chains 000000008022FE60 00000000000000B1
查看等待latch信息
select sid,p1raw,p2,p3,seconds_in_wait,wait_time,state from v$session_wait where event='latch: cache buffers chains'; SID P1RAW P2 P3 SECONDS_IN_WAIT WAIT_TIME STATE ---------- ---------------- ---------- ---------- --------------- ---------- ------------------- 29 000000008022FE60 177 0 234 0 WAITING 31 000000008022FE60 177 0 258 0 WAITING
执行awr快照
exec dbms_workload_repository.create_snapshot();
收集AWR,查看AWR:
具体查看:Events、SQL ordered by Gets、 Segments by Logical Reads等部分。
查看对于spid
select s.sid,s.serial#,p.spid from v$process p,v$session s where p.addr=s.paddr and s.username='CJC'; SID SERIAL# SPID ---------- ---------- ------------------------ 40 27 3010 31 29 3122 29 31 3234
收集dump
SQL> oradebug setospid 3234 Oracle pid: 33, Unix process pid: 3234, image: oracle@cjc-db-01 (TNS V1-V3) SQL> oradebug dump processstate 8 Statement processed. SQL> oradebug tracefile_name /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_3234.trc cp /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_3234.trc /home/oracle/tmp/
收集ssd
[oracle@cjc-db-01 ~]$ sqlplus -prelim "/as sysdba" SQL> oradebug setmypid SQL> oradebug unlimit SQL> oradebug dump systemstate 266 SQL> oradebug dump systemstate 266 SQL> oradebug tracefile_name /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_5519.trc cp /oracle/app/oracle/diag/rdbms/cjc/cjc/trace/cjc_ora_5519.trc /home/oracle/tmp/
简单看下
[root@cjc-db-01 ~]# vi /home/oracle/tmp/cjc_ora_3234.trc
搜索关键字:waiting for
waiting for 0x8022fe60 Child cache buffers chains level=1 child#=1797
可以看到等待的lath是0x8022fe60,也就是之前查到的000000008022FE60。 下面是客户端信息及Session Wait History信息。
client details: O/S info: user: oracle, term: pts/3, ospid: 3233 machine: cjc-db-01 program: sqlplus@cjc-db-01 (TNS V1-V3) application name: SQL*Plus, hash value=3669949024 Current Wait Stack: 0: waiting for 'latch: cache buffers chains' address=0x8022fe60, number=0xb1, tries=0x0 wait_id=29 seq_num=30 snap_id=1 wait times: snap=22 min 47 sec, exc=22 min 47 sec, total=22 min 47 sec wait times: max=infinite, heur=22 min 47 sec wait counts: calls=0 os=0 in_wait=1 iflags=0x2520 Wait State: fixed_waits=0 flags=0x28 boundary=0x813fb840/0 Session Wait History: elapsed time of 0.000028 sec since current wait 0: waited for 'SQL*Net message to client' driver id=0x62657100, #bytes=0x1, =0x0 wait_id=28 seq_num=29 snap_id=1 wait times: snap=0.000004 sec, exc=0.000004 sec, total=0.000004 sec wait times: max=infinite wait counts: calls=0 os=0 occurred after 0.000172 sec of elapsed time 1: waited for 'SQL*Net message from client' driver id=0x62657100, #bytes=0x1, =0x0
没有对应的holder信息。 释放latch
SQL> oradebug poke 0x000000008022FE60 4 0 BEFORE: [08022FE60, 08022FE64) = 00000001 AFTER: [08022FE60, 08022FE64) = 00000000
参考:
《Oracle内核技术揭秘》 云贝教育-详解oracle中的latch:cache buffer chains
###chenjuchao 20240907###
欢迎关注我的公众号《IT小Chen》
