- 事件参数说明:
事件号 | 事件名 | 参数一 | 参数二 | 参数三 |
145 | buffer busy waits | file# | block# | 9i - 原因码 10g - block class# |
- ORACLE会话正在等待PIN住一个缓冲区,会话必须在读取或修改缓冲区之前将该缓冲区PIN住。
- 在任何时侯只有一个进程可以PIN住一个缓冲区。
- buffer busy waits表明读/读、读/写、写/写争用。
- 根据P3中指明的原因码有不同的处理方式。
- 现象描述:会话在SGA中读取或修改缓冲区之前,必须要先获取cahce buffers chains锁存器(latch),获取后然后遍历这个缓冲区链,直到发现它需要的缓冲区头。然后以共享方式或独占方式获取该缓冲区锁或缓冲区头部的PIN,一旦缓冲区被PIN住,会话即释放cache buffers chains锁存器。如果无法获得PIN,会话就在buffer busy waits等待事件上等待。
- 该事件只与SGA中缓冲区相关,与会话私有的PGA中执行的读/写操作无关
--========================================================
此实验是不断的去更新同一个块中的不同记录,通过这种方式可以造成buffer
busy wait等待.
--创建测试表
create table test_db
(
ID NUMBER,
NICK VARCHAR2(30)
);
SQL> insert into test_db values(1,'zhaolin');
1 row created.
SQL> commit;
Commit complete.
SQL> insert into test_db values(2,'nature');
1 row created.
SQL> commit;
Commit complete.
SQL> select rowid,t.* from test_db t;
ROWID ID NICK
------------------ ---------- ------------------------------
AAAByLAAFAAAASuAAA 1 zhaolin
AAAByLAAFAAAASuAAB 2 nature
--检查这两条记录是否在同一个块上
SQL> select dbms_rowid.ROWID_RELATIVE_FNO(rowid)
file#,dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block# f
rom test_db;
FILE# BLOCK#
---------- ----------
5 1198
5 1198
--session 1
SQL> select sid from v$mystat where rownum<2;
SID
----------
11
declare
i number:=0;
begin
loop
update test_db set nick='session1' where id=1;
i:=i+1;
if mod(i,100)=0 then
commit;
end if;
end loop;
end;
--session 2
SQL> select sid from v$mystat where rownum<2;
SID
----------
12
declare
i number:=0;
begin
loop
update test_db set nick='session2' where id=2;
i:=i+1;
if mod(i,100)=0 then
commit;
end if;
end loop;
end;
--我们再启动会话session3
SQL> select s.sid,w.event from v$session s,v$session_wait w
2 where s.sid=w.sid
3 and s.status='ACTIVE';
SID EVENT
----------
----------------------------------------------------------------
1 pmon timer
2 rdbms ipc message
3 rdbms ipc message
4 control file sequential read
5 smon timer
6 rdbms ipc message
7 rdbms ipc message
8 wakeup time manager
9 rdbms ipc message
10 rdbms ipc message
11 buffer busy waits
SID EVENT
----------
----------------------------------------------------------------
12 latch free
18 SQL*Net message to client
13 rows selected.
SQL> /
SID EVENT
----------
----------------------------------------------------------------
1 pmon timer
2 rdbms ipc message
3 rdbms ipc message
4 rdbms ipc message
5 smon timer
6 rdbms ipc message
7 rdbms ipc message
8 wakeup time manager
9 rdbms ipc message
10 rdbms ipc message
11 latch free
SID EVENT
----------
----------------------------------------------------------------
12 buffer busy waits
18 SQL*Net message to client
13 rows selected.
注:这里出现的latch free是cache buffer chain latch等待,当会话11正在更
新块1198中记录时,会话12想去更新块1198中的不同记录时,这时会话12出现
buffer busy waits等待事件。当会话11更新块1198中记录完成,释放排它性的
pin,又要去获得cache buffer chain latch时,但此时会话12还没有以
exclusive的方式pin住1198块,所以会话12还没有释放cache buffer chain,因
为这样,会话11出现latch free等待!
--===================================
截至Oracle 9i,buffer busy waits事件的p1,p2,p3三个参数分别是file#,block#和id,分别表示等待的buffer block所在的文件编号,块编号和具体的等待原因编号,到了Oracle 10g,前两个参数没变,第3个参数变成了块类型编号,这一点可以通过查询v$event_name视图来进行验证:
PHP code:--------------------------------------------------------------------------------
Oracle 9i
SQL> select parameter1,parameter2,parameter3 from v$event_name where name='buffer busy waits';
PARAMETER1 PARAMETER2 PARAMETER3
------------------------ ------------------------ ------------------------
file# block# id
Oracle 10g
PARAMETER1 PARAMETER2 PARAMETER3
------------------------ ------------------------ ------------------------
file# block# class#
--------------------------------------------------------------------------------
在诊断buffer busy waits事件的过程中,获取如下信息会很有用:
1.获取产生buffer busy waits事件的等待原因编号,这可以通过查询该事件的p3参数值获得
P3 代表reason code,该值的具体意义表示如下:
| Code | Reason for wait | | - | A modification is happening on a SCUR or XCUR buffer but has not yet completed. | | 0 | The block is being read into the buffer cache. | | 100 | We want to NEW the block, but the block is currently being read by another session (most likely for undo). | | 110 | We want the CURRENT block either shared or exclusive but the block is being read into cache by another session, so we have to wait until itsread() is completed. | | 120 | We want to get the block in current mode, but someone else is currently reading it into the cache. Wait for the user to complete the read. This occurs during buffer lookup. | | 130 | Block is being read by another session, and no other suitable block image was found, so we wait until the read is completed. This may also occur after a buffer cache assumed deadlock. The kernel can't get a buffer in a certain amount of time and assumes a deadlock. Therefore it will read the CR version of the block. | | 200 | We want to NEW the block, but someone else is using the current copy, so we have to wait for that user to finish. | | 210 | The session wants the block in SCUR or XCUR mode. If this is a buffer exchange or the session is in discrete TX mode, the session waits for the first time and the second time escalates the block as a deadlock, so does not show up as waiting very long. In this case, the statistic: "exchange deadlocks" is incremented, and we yield the CPU for the "buffer deadlock" wait event. | | 220 | During buffer lookup for a CURRENT copy of a buffer, we have found the buffer but someone holds it in an incompatible mode, so we have to wait. | | 230 | Trying to get a buffer in CR/CRX mode, but a modificationhas started on the buffer that has not yet been completed. | | 231 | CR/CRX scan found the CURRENT block, but a modification has started on the buffer that has not yet been completed. |
|
按buffer类型分为四种:data block, segment header, undo header, undo block。确定访问哪个对象时出现buffer busy waits事件,可通过下面的方法进行定位
虽然buffer busy waits事件的发生可能至少有十个不同的原因,但是代码130和220是最常见的原因。基本上,小于200的代码号意味着这种等待是和I/O有关的。
带有原因码130的数据块(类#1)争用
1) 等待集中在数据块上,并且原因码是130,则意味着多个会话并发请求相同的数据块,但该数据块并不在缓冲存储器中,并且必须从磁盘读取。
2) 当多个会话请求不在缓冲存储器中的相同数据块时,ORACLE可以聪明地防止每个会话进行相同的操作系统I/O调用。否则,这可能严重地增加系统I/O的数量,所以,ORACLE只允许一个会话执行实际的I/O,而其他的会话在buffer busy waits上等待块,执行I/O的会话在db file sequential read或db file scattered read等待事件上等待。
3) 可在v$session视图中检查SESSION的注册时间,并且等待事件db file sequential(scattered) read和buffer busy waits等待相同的文件号和块号。
4) 解决方法:优化SQL语句,尽可能地减少逻辑读和物理读;
带有原因码220的数据块(类#1)争用
1) 等待集中在数据块上,并且原因码是220,则意味着多个会话同时在相同的对象上执行DML(相同块中的不同行)。
2) 如果数据块的尺寸较大(>=16K),则可能强化这种现象,因为较大的块一般在每个块中包含更多的行。
3) 减少这种情况的等待的方法:减少并发;减少块中行的数量;在另一个具有较小块尺寸的表空间中重新构建对象。
4) 具体方法说明:
使用较大的PCTFREE重新构建表或索引;
使用alter table minimize records_pre_block命令改变表以最小化每个块的最小行数
从ORACLE9i开始,可以在另一个具有较小块尺寸的表空间中移动或重新构建对象。
注:虽然这些方法可以最小化buffer busy waits问题,但它们无疑会增加全表扫描时间和磁盘空间利用率。
数据段头(类#4)的争用
1) 如果buffer busy waits的等待事件主要集中在数据段头(即表或索引段头,并且不是UNDO段头)上,这意味着数据库中一些表或索引有高段头活动。
注:进程出于两个主要原因访问段头,一是,获得或修改FREELISTS信息;二是,为了扩展高水位标记(HWM)。
2) 减少这种情况的等待的方法:
>> 对使用自由表进行段管理的表,增加确认对象的FREELISTS和FREELIST GROUPS(注:FREELIST GROUPS的增加也是必须的);
>> 确保FCTFREE和PCTUSED之间的间隙不是太小,从而可以最小化FREELIST的块循环。
>> 下一区的尺寸不能太小,当区高速扩张时,建立的新区需要修改在段头中区映射表。可以考虑将对象移动到合理的、统一尺寸的本地管理的表空间中。
撤销段头(类#17)的争用
1) 如果buffer busy waits等待事件主要集中在撤销段头,这表明数据库中的回滚段过少或者是它们的区尺寸太小,从而造成对段头的频繁更新。如果使用ORACLE9I的由数据库系统管理UNDO段,就不需要处理这种问题,因为ORACLE会根据需要增加额外的的UNDO段。
2) 可以创建并启用私有回滚段,以减少每个回滚段的事务数量。需要修改init.ora文件中的ROLLBACK_SEGMENTS参数。
3) 如果使用公用回滚段可以减少初始化参数transactions_per_rollback_segment的值,ORACLE通过transactions/transactions_per_rollback_segment来获取公有回滚段的最小数量。
撤销块的争用(类#18)
1) 如果buffer busy waits等待事件主要集中在撤销块上,这表明有多个并发会话为保证一致性读同时查询更新的数据。
2) 这是应用程序存在问题,当应用程序在不同时间内运行查询和DML时,这种问题不会存在。
附注:
一、查看系统所有段的有关buffer busy waits事件的统计:
SELECT *
FROM v$segment_statistics s
WHERE s.statistic_name = 'buffer busy waits'
AND s.owner <> 'SYS'