Sunteți pe pagina 1din 6

Free buffer waits 的等待原因一般有以下几个:

- DATA BUFFER 太小;


- DBWR 进程写的效率比较低;
- LGWR 写的太慢,导致 DBWR 等待;
- 正在把大量脏块写入到磁盘;
- SQL 语句效率低。
1、目前的 SGA 分配如下:
SQL> show sga;
Total System Global Area 8058284984 bytes
Fixed Size 740280 bytes
Variable Size 1073741824 bytes
Database Buffers 6979321856 bytes
Redo Buffers 4481024 bytes
2、通过查询 alert 日志未发现出错信息。
3、通过查询 v$system_event 发现等待确实严重:
SQL> select * from v$system_event where event like ‘free buffer waits’;
EVENT TOTAL_WAITS TOTAL_TIMEOUTS TIME_WAITED AVERAGE_WAIT
TIME_WAITED_MICRO
——————– ———– ————– ———– ———— —————–
free buffer waits 286242 273733 27360237 96 273602374180
通过查询 v$sql 和 v$sqlarea 发现如下 SQL 累计占用了最多的资源,尤其是 Buffer Gets:
1)SELECT COUNT (*) FROM (SELECT COUNTRYID FROM V_BAS_AIRPORTINT
WHERE AIRPORTID IN (:B2 , :B1 ) GROUP BY COUNTRYID);
– Total Per Execution Per Row
Executions 55,058,534 1 1.00
CPU Time (sec) 15,212.47 0.00 0.00
Buffer Gets 1,195,463,543 21.71 21.71
Disk Reads 78 0.00 0.00
Rows 55,057,959 1.00 1
Fetches 55,058,578 1.00 1.00

2)SELECT COUNT (A.ABNRECID) FROM T_ABN_BILLREG A,V_USR_P_OPEDEPART


B,T_ABN_ABNTYPE C,T_AWB_WAYBILLBAS D,T_ABN_BILLOPE E WHERE A.OPEDE
PARTID=B.OPEDEPARTID AND A.ABNTYPE=C.ABNTYPE AND A.BILLID=D.BILLID(+)
AND A.OPEDATE BETWEEN B.VALIDSTARTDT AND B.VALIDENDDT AND A.ABNRECI
D=E.ABNRECID(+) AND A.AIRLINEID= :B5 AND A.FLIGHTNO= :B4 AND A.FLIGHT_
DATE = :B3 AND A.FLTSAIRPORT=:B2 AND A.FLTEAIRPORT=:B1

3)SELECT COUNT (A.ABNRECID) FROM T_ABN_BILLREG A,V_USR_P_OPEDEPART


B,T_ABN_ABNTYPE C,T_AWB_WAYBILLBAS D,T_ABN_BILLOPE E WHERE A.OPED
EPARTID=B.OPEDEPARTID AND A.ABNTYPE=C.ABNTYPE AND A.BILLID=D.BILLID(+)
AND A.OPEDATE BETWEEN B.VALIDSTARTDT AND B.VALIDENDDT AND A.ABNRE
CID=E.ABNRECID(+) AND F_ABN_EOPE_BILLREG(A.ABNRECID)=’N’ AND A.AIRLIN
EID= :B5 AND A.FLIGHTNO = :B4 AND A.FLIGHT_DATE = :B3 AND A.FLTS…
4)SELECT TYPE FROM T_USR_OPEDEPART WHERE DELYES=’N’ AND (SYSDATE<VALI
DENDDT OR VALIDENDDT IS NULL) AND (SYSDATE>VALIDSTARTDT OR VALIDSTAR
TDT IS NULL) AND OPEDEPARTID=:B1

5)SELECT COUNT(*) FROM T_ABN_BILLOPE WHERE ABNRECID =:B1 AND FINYES


=’Y’;

6)SELECT COUNT(*) FROM T_FLT_FDLOG WHERE AIRLINEID =:B3 AND FLIGHTNO


= :B2 AND FLIGHTDATE = :B1 AND (INSTR(MODTYPE,’A') > 0 OR
INSTR(MODTYPE,’B') > 0 );

7)select lastupdatetime from t_bas_lastupdate where basviewname = :1

结论:
db cache 用尽以及 IO 性能低下的情况下,数据库不能及时地将缓存中的脏数据块写入到数
据文件以腾出内存区域,因此导致了大量的等待,其中 IO 在 Free buffer waits 事件出现的
时候基本上达到满负荷,DATA BUFFER 虽然增加过但仍然相对过小,导致很多新的需求
根本无法请求内存,因此 Free buffer waits 事件频繁出现。
建议:
对 TOP SQL 进行优化,后面会有针对 TOP SQL 的 cache 及 mview 的案例。
如果不能优化,那么 Free buffer waits 事件的操作建议仍然是增加 DATA BUFFER 的大小。

当会话意图访问缓冲存储器中的数据块,而该数据块正在被其它会话使用时产生 buffer
busy waits 事件。其它会话可能正在从数据文件向缓冲区存储器度曲同样的数据块,或正在
缓冲存储器中对其进行修改。
为了确保读取器会话拥有与获得所有更改或无更改的数据块一致的映像,正在修改该数
据块的会话在其标题中标记一个标志,让其他会话知道有一个更改正在进行而等候更改的
的完成。
视图 v$waitstat 不是 OWI 的组件,但其为没一类缓冲区提供了有用的等待统计。遭遇
buffer busy 等待事件最常见的缓冲区类为块、段标题、撤消块、撤消标题。
显示一个查询 v$waitstat 视图的采样输出:
具体示例如下:
SELECT * FROM V$waitstat WHERE COUNT>0;
CLASS COUNT TIME
------------------ ---------- ----------
data block 4170082 1668098
segment header 116 98
undo header 916 1134
undo block 2087 1681
1、等待参数
buffer wait busy 的等待参数描述如下:
P1 在 Oracle 8 及其以后版本的数据库里,P1 显示询问数据块驻留的绝对文件号。
P2 进程需要访问的实际块号。
P3 在 Oracle10g 以前的版本中,着是表示等待原因的数字。Oracle 在内河代码中在
多个地方用不同的原因码提交。该原因码取决于版本。
2、等待时间
100 厘秒或 1 秒。
。 Oracle 会话正在等待钉住一个缓冲区。必须在读取或修改缓冲区前将它钉住。在任何
时刻只有一个进程可以钉住一个缓冲区。
。buffer busy waits 表明读/读、读/写、写/写争用。
。采取的适当措施取决于 P3 参数中的原因码。
在 SGA 中读取或修改缓冲区的会话必须首先获取 cache buffers chains 锁存器,并且遍历
这个缓冲区链,直到他发现必需的缓冲区头。然后,他必须以共享模式或独占模式获取
一个缓冲区锁或缓冲区头上的 pin,这取决于他计划的操作。一旦缓冲区头被钉住,会话
就释放 cache buffers chains 锁存器,并在缓冲区自身上执行计划的操作。如果无法获
取一个 pin,会话就在 buffer busy waits 等待事件上等待。这种等待时间不会应用于在
会话的私有 PGA 中执行的读取或写入操作。
3、诊断的原因、诊断和动作
。表示为什么进程无法获得一个缓冲区 pin 的主要原因码。
。buffer busy waits 等待时间需要的块类。
。和 buffer busy waits 时间相关的 SQL 语句。
。缓冲区所属的段。
——查找等待块类型
SELECT 'segment Header' CLASS,
a.Segment_Type,
a.Segment_Name,
a.Partition_Name
FROM Dba_Segments a,
V$session_Wait b
WHERE a.Header_File = b.P1
AND a.Header_Block = b.P2
AND b.Event = 'buffer busy waits'
UNION
SELECT 'freelist Groups' CLASS,
a.Segment_Type,
a.Segment_Name,
a.Partition_Name
FROM Dba_Segments a,
V$session_Wait b
WHERE b.P2 BETWEEN a.Header_Block + 1 AND (a.Header_Block + a.Freelist_Groups)
AND a.Header_File = b.P1
AND a.Freelist_Groups > 1
AND b.Event = 'buffer busy waits'
UNION
SELECT a.Segment_Type || ' Block' CLASS,
a.Segment_Type,
a.Segment_Name,
a.Partition_Name
FROM Dba_Extents a,
V$session_Wait b
WHERE b.P2 BETWEEN a.Block_Id AND a.Block_Id + a.Blocks - 1
AND a.File_Id = b.P1
AND b.Event = 'buffer busy waits'
AND NOT EXISTS (SELECT 1
FROM Dba_Segments
WHERE Header_File = b.P1
AND Header_Block = b.P2);

1) 带有原因码 130 的数据块(类#1)争用


如果 buffer busy waits 的等待事件主要集中在数据块(类#1)上,并且原因码 130,则
表明应用程序运行在同一时刻查询相同数据集的多个会话,采用如下三件事最小化问题:
a. 减少并发级别或该表在运行现成直接内分区工作的方法。
b. 优化 SQL 语句,减少物理读取和逻辑读取的数量。
c. 增加 freeLists 和 freeList Groups 的数量。
2) 带有原因码 220 的数据块(类#1)争用
a. 多个会话同时在相同的对象上 DML.采用如下三件事最小化问题:
b. 减少并发级别或改变划分部分的方法。
c. 减少块中行的数量。
在另一个具有较小块尺寸的表空间中重新构建对象(Oracle 9i 或以上版本)。
可以使用较大的 PCTFREE 重新构建表或索引。可以使用命令改变表以最小化每个块的最
小行数:
ALTER TABLE table_name MINIMIZE RECORDS_PER_BLOCK;
从 Oracle 9i 开始,可以在另外一个具有较小的块尺寸的表空间中移动或重新构建对象。
虽然这些动作可以最小化 buffer busy waits 问题,但是他们无疑将增加全表扫描时间
和磁盘空间利用率。常言道,世上没有免费的午餐。
3) 数据段头(类#4)的争用
如果 buffer busy waits 的等待时间主要集中在数据段头(即表或索引段头,并且不是
插销段头)上,这意味着数据库中的一些表或索引具有高段头活动。如下解决问题:
a. 增加已经确定对象的进程 FreeLists 和 FreeList Groups 的数量。
b. 确保 PctFree 和 PctUsed 之间内的间隙不会太小。
c. 确保下一个区尺寸不会太小。
如果不希望混浠 FreeLists 和 FreeList Groups,可以依靠自动段空间管理(Automatic
Segment Space Management,ASSM)特性,以分散从插入语句中引入的数据(9i 特性)。
4) 撤消段都(类#17)的争用
如果 buffer busy waits 等待时间主要集中在撤消段头上,这表明数据库中的回滚段过少,
或者他们的尺寸太小,从而造成对段头的频繁更新。如果在 Oracle 9i 中引入的系统管理
撤消,就不需要处理这种问题,因为 Oracle 将根据需要增加额外的撤消段。
5) 撤消块的争用(类#18)
如果 buffer busy waits 等待时间主要集中在撤消块上,这通常意味着多个并发会话同时
查询更新的数据。当应用程序可以在不同的时间内查询和 DML 时,这种问题就不会存
在。

系统级诊断 ——文件等待次数
SELECT b.File_Id,b.File_Name,a.COUNT FROM X$kcbfwait a,Dba_Data_Files b
WHERE a.Indx = b.File_Id-1 AND a.COUNT > 0 ORDER BY a.COUNT;

连接到数据库发现了大量的 free buffer waits 和 buffer busy waits。


SQL> select event,count(*) from v$session group by event;
EVENT COUNT(*)
---------------------------------------------------------------- ----------
SQL*Net message from client 249
free buffer waits 28
buffer busy waits 12
free buffer waits 是由于进程请求 buffer 在 cache buffer lru list 链表中请求不到 free buffer 存储
需要的 block buffer 导致,可以考虑如下方式:
1 增加 cache buffer 的大小
2 增加 ckpt 和 dbwn 写入 dirty buffer 的效率.,o 默认的参数一般是合适的,不优先考虑。
3 减少 process 请求的 buffer 的容量,例如减少 process 的 sql 语句的逻辑读。
查看下 sga 的大小,2g 实在是太小了,考虑到内存 16g 故增加 sga 到 11g
SQL> show parameter sga_target;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
sga_target big integer 2G
SQL> alter system set sga_max_size=11g scope=spfile;
System altered.
关注下 buffer busy waits 等待事件
SQL> select p1text,p1,p2text,p2, p3text,p3 from v$session where event='buffer busy waits' and
Rownum<10;
P1TEXT P1 P2TEXT P2 P3text p3
---------- ---------- ---------- ----------
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
file# 30 block# 242393 class# 1
(该对象是个 index block,而且是个主键的 index 造成,这个 buffer busy waits 等待是由于
主键递增插入数据导致 buffer 被争用)
关于 buffer busy waits 等待事件的描述:
1 session 会先进行 cache buffer 的计算得到一个 hash value,然后遍历对应的 cache buffer
chains,查看是否存在对应的 buffer,此时会需要获取 cache buffer chains latch,当该 cache
buffer 对应的 chains latch 不能及获取则会出现 cache buffer chains latch 等待。
2 获取到 cbc latch 后,会根据 cbc 的 buffer header 去 cache buffer lru list 上 pin/lock 该 buffer,
然后释放 cbc latch。
3 如果此时 buffer 被其他进程并发的不兼容模式占用则会出现 buffer busy waits 等待。而占用
buffer busy waits 的 session 可能在经历着 db file sequential read 或者 db file scattered read 等待。
而对于不同的 buffer busy wait 的 p3 参数会有不同的处理方式,而这里小鱼碰见的 p3text
class 等于 1 是关于 block contention,也就是 block 的热点现象,主要有内存的 buffer 的热点
和 disk 的 buffer 热点,10g 后分离出 disk 的 buffer 热点为一个新的等待事件也就是 read by
other sessions。
在 10g 后由于引入了 assm 管理,位图代替了原来的 freelist 列表,一般主要是块头和块的
buffer 请求造成 buffer busy waits,可以通过下列语句查看 buffer busy waits 等待的块类型。
SELECT 'segment Header' CLASS, a.Segment_Type, a.Segment_Name, a.Partition_Name
FROM Dba_Segments a, V$session_Wait b WHERE a.Header_File = b.P1 AND a.Header_Block
= b.P2 AND b.Event = 'buffer busy waits'
SELECT a.Segment_Type || ' Block' CLASS, a.Segment_Type, a.Segment_Name, a.Partition_Na
me FROM Dba_Extents a, V$session_Wait b WHERE b.P2 BETWEEN a.Block_Id AND a.Block
_Id + a.Blocks – 1 AND a.File_Id = b.P1 AND b.Event = 'buffer busy waits' AND NOT EXISTS
(SELECT 1 FROM Dba_Segments WHERE Header_File = b.P1 AND Header_Block = b.P2);
相应的处理方式可以考虑:
1 减小系统的并发请求,对于开启并行 DML 操作可以减少该 block 涉及的 object 并行度。
2 找到 buffer 对应的 object,减小其 object 涉及 sql 语句的逻辑读消耗。
3 分散 segment 的数据分布:例如根据对象类型用分区表(hash 分区)或者分区索引(hash 分
区)打散 IO 请求分布到不同的 block;反转索引打散 index 的 IO 请求;可以增加 pctfree 参数减
少 block 存储的数据记录;或者设置 alert table tablenam Minimize records_per_block 改变块的
存储记录行。
采用第三种方式无疑会增加 fts 的消耗,而且只对后面使用的 block 生效,分区表在线重定
义会有短暂锁表时间,而且大表在线重定义也是很慢的。一般优先考虑减小并行和并发,
优化 sql 的逻辑读,db 大多数问题可以说大都都是因为不良的 sql 导致的。
最终采取增加了 sga 的大小,重新启动数据库,而后调整了该索引为 hash 分区,等待事件
基本消失,性能得到一定提升。

S-ar putea să vă placă și