一、等待事件介绍
This event occurs when a session requests a buffer that is currently being read into the buffer cache by another session. Prior to release 10.1, waits for this event were grouped with the other reasons for waiting for buffers under the 'buffer busy wait' event
Wait Time: Time waited for the buffer to be read by the other session (in microseconds)
这个事件发生在一个数据块正在被读进buffer,而其它session此时也要请求这个数据块的时候。这个事件10G以前被归类在buffer busy wait的其他类目中。
二、查看数据库read by other session和db file sequential read的等待事件的信息
脚本:
select sid, serial#, username, status, machine, program, sql_hash_value, sql_id, to_char(logon_time,'yyyy-mm-dd hh24:mi:ss'), event, p1, p2, p3 from v$session where event in ('read by other session', 'db file sequential read'); |
三、查看read other session和db file scattered read事件相关语句的SQL_ID
SQL>select distinct sql_id From v$session Where event in('read by other session', 'db file sequential read');
bppda1x0f8hm6 725qd4af6qhsc dtuvu8d68ztap grzps7akjm1w4 b2btxkx04vb30 336yj7rvwzvm2 b4h4ma591drgj 8xq8qwupb73pg bzagvp1s5kvjv |
四、查看相关语句的执行计划
select * from table(dbms_xplan.display_awr('bppda1x0f8hm6'));
SQL_ID bzagvp1s5kvjv -------------------- SELECT "BUKRS", "GJAHR", "PERIO" "MONAT", "KSTAR" "HKONT", "WTGBTR", "BEKNZ", "OBJNR" FROM "COEP" WHERE "MANDT"=:A0 AND "BUKRS"=:A1 AND "VRGNG" IN (:A2 ,:A3 ) AND "BEKNZ" IN (:A4 ,:A5 ) AND ("GJAHR"=:A6 OR "GJAHR"=:A7 ) AND "FKBER"=:A8
Plan hash value: 1832698800
|
可以看到相关SQL确实在对该表做索引扫描的操作,耗时达到23分钟。
五、解决方法
1、对SQL语句进行调优;
2、调节数据库的buffer cache,因为这个过程是指内存中找不到相应的数据,所以要从磁盘把数据读取到共享内存,如果是由于buffer cache太小的话,增加buffer cache的大小便可以解决这个问题(需要参照awr报告中的内存命中率情况)
附加:
Read By Other Session详细原理说明:这个等待在10G前就是Buffer Busy Waits等待的一种情况,10G后把这个等待从Buffer Busy Waits等待的划分了出来。总的来说,这个等待的发生在由于:进程(我们假设进程A)需要访问的数据块不在内存里,因此不得不把数据块从磁盘LOAD到内存的过程中,另一个/些(假设进程B、C)也要读取这个数据块,这个时候进程A发生的等待可能是db file sequential read/db file parallel read/db file scattered read中的某一个或某几个,而进程B、C发生的等待就是我们今天要介绍的Read By Other Session,Oracle不会让多个进程去同时物理读取一个数据块LOAD入共享内存,只会让第一个进程去DISK读取,然后放入共享内存,这么做也是为了保护共享内存。
步骤大致如下:1)Oracle计算出查询所要请求数据块的地址,然后根据地址+块类计算出块所在buffer cache的Hash Bucket Number,然后获取到保护这个Hash Bucket的CBC Latch,在持有CBC Latch的情况下,在Hash Bucket里寻找目标Block是否存在在Bucket里,最终没有找到,释放CBC Latch。(可能Oracle 实际发生的情况与我描述的不符,看最后的解释)。2)申请Lru Latch,搜索Lru-Aux链表找寻空闲块。其实这个链表是以buffer header上的指针串起来的,buffer header上还有指向buffer block的指针,找到后,修改buffer header的某些条目,比如把block address的信息设置上去,指向内存里的某个buffer,主要是标示内存里的这个块已经被使用了。3)再次获取正确的CBC Latch,把这个buffer header链接到正确的hash chain上去,也就是把它放到正确的hash bucket里去。4)以排他的x模式去pin这个buffer。这样别的会话就能知道这个buffer还不能访问。5)释放Lru Latch,CBC Latch.6)开始物理读取,这个时候前台进程等待db file sequential read/db file parallel read/db file scattered read ,具体等待那一种,看读取的类型,也可能会出现多种等待。7)在物理读取期间,如果有其他会话也想访问这个数据块,等待Read By Other Session 。8)读取结束后,申请CBC Latch,unpin这个buffer,释放CBC Latch。
10G前把这个等待归入到了Buffer Busy Waits等待里,这么归类也是有道理的:Buffer Busy Waits等待的本质是由于欲获得buffer lock的会话由于申 请的锁模式跟buffer上已经存在的锁模式冲突导致的。而read by other session也符合这一核心要点。物理读取数据块的进程在对应的buffer上加了x模式的buffer lock,其他进程想要以s模式读取数据块,由于x模式的buffer lock,与任何其他锁模式都不兼容,因此产生了read by other session等待,也就是10G前的buffer busy waits等待中的一种情形。直接路径读取会不会产生read by other session?不会的,直接路径读取把数据读取在进程自己的PGA里,不涉及到共享内存的占用,这种情况下,即使有并发,各个进程间的等待也只是 direct path read。步骤1我的描述里,进程在发现数据块不在内存后,释放了CBC Latch,然后去申请Lru Latch,获得空闲内存块后,再次去持有CBC Latch,而这个过程也非常可能是进程在发现数据块不在内存后,不释放CBC Latch,直接去持有Lru Latch。至于到底是哪个过程,我就不做验证了,有兴趣的可以去手工的持有latch验证下。我个人觉得不释放CBC Latch,直接去持有Lru Latch的可能性比较大:1)这样省去了释放CBC Latch最后又获得一次CBC Latch的资源消耗 2)Lru的Latch的级别设计的比CBC Latch级别高,因此在持有CBC Latch的情况下再去持有Lru Latch更显得顺理成章。当然这个只是我YY,理论上持有Lru Latch情况下,以immediate 方式去申请CBC Latch也是可以的。这里只是给大家大体介绍一下这个等待的一些基本情况,更深的细节暂时就不过多研究了。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
本文作者:JOHN
ORACLE技术博客:ORACLE 猎人笔记 数据库技术群:367875324 (请备注ORACLE管理 )
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++