首页 > 代码库 > Oracle Study之--Oracle等待事件(1)

Oracle Study之--Oracle等待事件(1)

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来记录数据库自启动以来所有等待事件的汇总信息。通过这个视图,用户可以迅速获得数据库运行的总体概况。

wKioL1PQ0pGRCy2LAAHasLaUnl8973.jpg

wKiom1PQ0XeA5zBUAAFvCanL6ks072.jpg



二. 常见的等待事件
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 image 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


====未完,待续===