Oracle Study之--Oracle等待事件(1)
一. 等待事件的相关知识
1.1 等待事件主要可以分为两类:
即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件。
1). 空闲等待事件指ORACLE正等待某种工作,在诊断和优化数据库的时候,不用过多注意这部分事件。
2). 非空闲等待事件专门针对ORACLE的活动,指数据库任务或应用运行过程中发生的等待,这些等待事件 是在调整数据库的时候需要关注与研究的。
在Oracle 10g中的等待事件有874个,11g中等待事件1118个。 我们可以通过v$event_name 视图来查看等待事件的相关信息。
10gR2: [oracle@aix211 ~]$sqlplus '/as sysdba' SQL*Plus: Release 10.2.0.1.0 - Production on Thu Jul 24 14:44:43 2014 Copyright (c) 1982, 2005, Oracle. All rights reserved. Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production With the Partitioning, OLAP and Data Mining options SQL> desc v$event_name Name Null? Type ----------------------------------------- -------- ---------------------------- EVENT# NUMBER EVENT_ID NUMBER NAME VARCHAR2(64) PARAMETER1 VARCHAR2(64) PARAMETER2 VARCHAR2(64) PARAMETER3 VARCHAR2(64) WAIT_CLASS_ID NUMBER WAIT_CLASS# NUMBER WAIT_CLASS VARCHAR2(64) SQL> select count(*) from v$event_name; COUNT(*) ---------- 874 11gR2: [oracle@rh6 ~]$sqlplus '/as sysdba' SQL*Plus: Release 11.2.0.1.0 Production on Thu Jul 24 14:54:35 2014 Copyright (c) 1982, 2009, Oracle. All rights reserved. Connected to an idle instance. 14:55:04 SYS@ prod>select count(*) from v$event_name; COUNT(*) ---------- 1118 Elapsed: 00:00:00.0
1.2 查看等待事件的分类
14:55:18 SYS@ prod> SELECT wait_class#, 14:58:50 2 wait_class_id, 14:58:50 3 wait_class, 14:58:50 4 COUNT ( * ) AS "count" 14:58:50 5 FROM v$event_name 14:58:50 6 GROUP BY wait_class#, wait_class_id, wait_class 14:58:50 7 ORDER BY wait_class#; WAIT_CLASS# WAIT_CLASS_ID WAIT_CLASS count ----------- ------------- ------------------------------ ---------- 0 1893977003 Other 719 1 4217450380 Application 17 2 3290255840 Configuration 24 3 4166625743 Administrative 54 4 3875070507 Concurrency 32 5 3386400367 Commit 2 6 2723168908 Idle 94 7 2000153315 Network 35 8 1740759767 User I/O 45 9 4108307767 System I/O 30 10 2396326234 Scheduler 7 11 3871361733 Cluster 50 12 644977587 Queueing 9 13 rows selected.
1.3 相关的视图
V$SESSION:代表数据库活动的开始,视为起源,连接断开后消失。
V$SESSION_WAIT:视图用以实时记录活动SESSION的等待情况,是当前信息,断开后消失(等待会话生命周期最后1次等待)。
V$SESSION_WAIT_HISTORY:是对V$SESSION_WAIT的简单增强,记录活动SESSION的最近10次等待。
V$SQLTEXT:当数据库出现瓶颈时,通常可以从V$SESSION_WAIT找到那些正在等待资源的SESSION,
通过SESSION的SID,联合V$SESSION和V$SQLTEXT视图就可以捕获这些SESSION正在执行的SQL语句。
V$ACTIVE_SESSION_HISTORY:是ASH的核心,用以记录活动SESSION的历史等待信息,每秒采样一次,这部分内容记录在内存中,期望值是记录一个小时的内容。
WRH#_ACTIVE_SESSION_HISTORY: 是V$ACTIVE_SESSION_HISTORY在AWR的存储地。
V$ACTIVE_SESSION_HISTORY中 的信息会被定期(每小时一次)的刷新到负载库中,并缺省保留一个星期
用于分析。
DBA_HIST_ACTIVE_SESS_HISTORY:视图是WRH#_ACTIVE_SESSION_HISTORY视图和其他几个视图的联合展现,通常通过这个视图进行历史数据的访问。
V$SYSTEM_EVENT: 由于V$SESSION记录的是动态信息,和SESSION的生命周期相关,而并不记录历史信
息,所以ORACLE提供视图V$SYSTEM_EVENT来记录数据库自启动以来所有等待事件的汇总信息。通过这个视图,用户可以迅速获得数据库运行的总体概况。
二. 常见的等待事件
2.1. Buffer busy waits
从本质上讲,这个等待事件的产生仅说明了一个会话在等待一个Buffer(数据块),但是导致这个现象的原因却有很多种。
常见的两种是:
· 当一个会话试图修改一个数据块,但这个数据块正在被另一个会话修改时。
· 当一个会话需要读取一个数据块,但这个数据块正在被另一个会话读取到内存中时。
Oracle 操作的最小单位是块(Block),即使你要修改一条记录,也需要对这条记录所在的这个数据块做操作。 当你对这个数据块做修改时,其他的会话将被阻止对这个数据块上的数据做修改(即使其他用户修改的不是当前用户修改的数据),但是可以以一致性的方式读取这个数据块(from undo)。当前的用户修改完这个数据块后,将会立即释放掉加在这个数据块上的排他锁,这样另一个会话就可以继续修改它。修改操作是一个非常短暂的时间,这种加锁的机制我们叫Latch。
当一个会话修改一个数据块时,是按照以下步骤来完成的:
· 以排他的方式获得这个数据块(Latch)
· 修改这个数据块。
· 释放Latch。
Buffer busy waits等待事件常见于数据库中存在热块的时候,当多个用户频繁地读取或者修改同样的数据块时,这个等待事件就会产生。 如果等待的时间很长,我们在AWR或者statspack 报告中就可以看到。
这个等待事件有三个参数。查看有几个参数我们可以用以下SQL:
15:08:43 SYS@ prod>col name for a30 15:08:51 SYS@ prod>col PARAMETER1 for a20 15:08:58 SYS@ prod>col PARAMETER2 for a20 15:09:05 SYS@ prod>col PARAMETER3 for a20 15:09:12 SYS@ prod>r 1 SELECT name, 2 parameter1, 3 parameter2, 4 parameter3 5 FROM v$event_name 6* WHERE name = 'buffer busy waits' NAME PARAMETER1 PARAMETER2 PARAMETER3 ------------------------------ -------------------- -------------------- ---------------- buffer busy waits file# block# class# Elapsed: 00:00:00.02
在下面的示例中,查询的方法和这个一样,所以其他事件对参数的查询将不做过多的说明。
File#: 等待访问数据块所在的文件id号。
Blocks: 等待访问的数据块号。
ID: 在10g之前,这个值表示一个等待时间的原因,10g之后则表示等待事件的类别。
Buffer Busy Waits 案例:
1)创建对象 15:55:32 SCOTT@ test1>create table t1 (id int,name varchar2(10)); Table created. Elapsed: 00:00:00.13 15:55:54 SCOTT@ test1>begin 15:55:56 2 for i in 1..100 loop 15:56:09 3 insert into t1 values (i,'usr'||i); 15:56:27 4 end loop; 15:56:31 5 end; 15:56:32 6 / PL/SQL procedure successfully completed. Elapsed: 00:00:00.28 15:56:33 SCOTT@ test1>commit; Commit complete. Elapsed: 00:00:00.04 15:56:36 SCOTT@ test1>grant all on t1 to tom; Grant succeeded. Elapsed: 00:00:00.12 2)多个事务同时访问同一个对象 scott 用户做DML操作: 15:58:18 SYS@ test1>conn scott/tiger Connected. 15:58:22 SCOTT@ test1>begin 15:59:36 2 15:59:36 3 for i in 1..100000 loop 15:59:36 4 update t1 set name='scott' where id=1; 15:59:36 5 commit; 15:59:36 6 end loop; 15:59:36 7 end; 15:59:38 8 / tom用户做DML操作: 15:58:28 SYS@ test1>conn tom/tom Connected. 15:58:32 TOM@ test1>begin 15:59:52 2 15:59:52 3 for i in 1..100000 loop 15:59:52 4 update scott.t1 set name='tom' where id=2; 15:59:52 5 commit; 15:59:52 6 end loop; 15:59:52 7 end; 15:59:53 8 / 3)查看会话产生的waits 15:56:52 SCOTT@ test1>conn /as sysdba Connected. 15:58:54 SYS@ test1>select username,sid,serial# from v$session where username is not null; USERNAME SID SERIAL# ------------------------------ ---------- ---------- SYS 1 28 SCOTT 29 9 TOM 41 50 Elapsed: 00:00:00.24 16:12:48 SYS@ test1>select event,sid,p1,p2,p3 from v$session_wait where sid in (29,41) EVENT SID P1 P2 P3 ---------------------------------------- ---------- ---------- ---------- ---------- log file switch (archiving needed) 29 0 0 0 buffer busy waits 41 4 173 1 Elapsed: 00:00:00.04 产生buffer busy waits的对象在file#为4,block_id为173上 16:00:57 SYS@ test1>select * from v$waitstat where count>0; CLASS COUNT TIME ------------------ ---------- ---------- data block 67 6516 segment header 1 0 undo header 6 1 undo block 1 1 Elapsed: 00:00:00.03 data block产生大量的等待 ! 16:01:00 SYS@ test1>select sql_text from V$sqlarea where (address,hash_value) in (select sql_address,sql_hash_value from v$session where event like '%buffer busy%'); SQL_TEXT ---------------------------------------------------------------------------------------- UPDATE SCOTT.T1 SET NAME='tom' WHERE ID=2 Elapsed: 00:00:00.44 在scott的t1表上产生了热块 ! 16:04:12 SYS@ test1>select sql_text from v$sqlarea where sql_text like '%t1%'; SQL_TEXT ------------------------------------------------------------------------------------------- begin for i in 1..100000 loop update t1 set name='scott' where id=1; commit; end loop; end; begin for i in 1..100000 loop update scott.t1 set name='tom' where id=2; commit; end loop; end; 16:05:07 SYS@ test1>select sql_text from v$sqlarea where sql_text like '%t1%'; SQL_TEXT ------------------------------------------------------------------------------------------- begin for i in 1..100000 loop update t1 set name='scott' where id=1; commit; end loop; end; begin for i in 1..100000 loop update scott.t1 set name='tom' where id=2; commit; end loop; end; 查看scott用户对象t1所在的块:(168-175) 16:16:36 SYS@ test1>select owner,SEGMENT_NAME,SEGMENT_TYPE,FILE_ID,BLOCK_ID,BLOCKS from dba_extents 16:16:40 2 where segment_name='T1' and owner='SCOTT'; OWNER SEGMENT_NAME SEGMENT_TYPE FILE_ID BLOCK_ID BLOCKS ------------------------------ -------------------- ------------------ ---------- ---------- ---------- SCOTT T1 TABLE 4 168 8 Elapsed: 00:00:00.80
2. Buffer latch
内存中数据块的存放位置是记录在一个hash列表(cache buffer chains)当中的。当一个会话需要访问某个数据块时,它首先要搜索这个hash 列表,从列表中获得数据块的地址,然后通过这个地址去访问需要的数据块,这个列表Oracle会使用一个latch来保护它的完整性。 当一个会话需要访问这个列表时,需要获取一个Latch,只有这样,才能保证这个列表在这个会话的浏览当中不会发生变化。
产生buffer latch的等待事件的主要原因是:
· Buffer chains太长,导致会话搜索这个列表花费的时间太长,使其他的会话处于等待状态。
· 同样的数据块被频繁访问,就是我们通常说的热块问题。
产生buffer chains太长,我们可以使用多个buffer pool的方式来创建更多的buffer chains,或者使用参数DB_BLOCK_LRU_LATCHES来增加latch的数量,以便于更多的会话可以获得latch,这两种方法可以同时使用。
这个等待事件有两个参数:
Latch addr: 会话申请的latch在SGA中的虚拟地址。
通过以下的SQL语句可以根据这个地址找到它对应的Latch名称:
select * from v$latch a,v$latchname b where
addr=latch addr -- 这里的latch addr 是你从等待事件中看到的值
and a.latch#=b.latch#;
chain#: buffer chains hash 列表中的索引值,当这个参数的值等于s 0xfffffff时,说明当前的会话正在等待一个LRU latch。
案例:
16:56:47 SYS@ test1>select * from v$latchname where upper(name) like '%BUFFER%'; LATCH# NAME HASH ---------- ---------------------------------------------------------------- ---------- 33 SGA IO buffer pool latch 2719726273 63 IPC stats buffer allocation latch 1449990452 106 KJC global post event buffer 3098969798 145 cache buffers lru chain 3559635447 146 buffer pool 510014793 150 cache buffers chains 3563305585 151 cache buffer handles 892398878 196 media recovery process out of buffers 2731251867 197 mapped buffers lru chain 93631960 208 lock DBA buffer during media recovery 3620457631 350 virtual circuit buffers 1577520421 378 parallel query alloc buffer 291345605 416 p_w_picpath handles of buffered messages latch 3223585260 441 KWQMN to-be-Stopped Buffer list Latch 3064249245 476 buffer pin latch 3925519355 15 rows selected. Elapsed: 00:00:00.02 16:57:39 SYS@ test1>desc v$latch Name Null? Type ----------------------------------------------------------------- -------- -------------------------------------------- ADDR RAW(8) LATCH# NUMBER LEVEL# NUMBER NAME VARCHAR2(64) HASH NUMBER GETS NUMBER MISSES NUMBER SLEEPS NUMBER IMMEDIATE_GETS NUMBER IMMEDIATE_MISSES NUMBER WAITERS_WOKEN NUMBER WAITS_HOLDING_LATCH NUMBER SPIN_GETS NUMBER SLEEP1 NUMBER SLEEP2 NUMBER SLEEP3 NUMBER SLEEP4 NUMBER SLEEP5 NUMBER SLEEP6 NUMBER SLEEP7 NUMBER SLEEP8 NUMBER SLEEP9 NUMBER SLEEP10 NUMBER SLEEP11 NUMBER WAIT_TIME NUMBER 16:58:18 SYS@ test1>select addr,name,hash,gets,misses from v$latch where hash='3559635447'; ADDR NAME HASH GETS MISSES ---------------- ---------------------------------------------------------------- ------- 00000000600188A8 cache buffers lru chain 3559635447 359628 36 Elapsed: 00:00:00.03 16:59:03 SYS@ test1>select addr,name,hash,gets,misses from v$latch where hash in ('3559635447','3563305585','892398878'); ADDR NAME HASH GETS MISSES ---------------- ---------------------------------------------------------------- ------- 00000000600188A8 cache buffers lru chain 3559635447 359652 36 000000006001A620 cache buffers chains 3563305585 43311894 21 000000006001A6C8 cache buffer handles 892398878 368 0 Elapsed: 00:00:00.03
====未完,待续===