oracle等待事件2构造一个DB File Sequential Read等待事件和构造一个Direct Path Read

第一篇 《oracle等待事件1分别用表和索引上数据的访问来产生db file scattered read等待事件》http://leonarding.blog.51cto.com/6045525/1105411
第二篇 《oracle等待事件2构造一个DB File Sequential Read等待事件和构造一个Direct Path Read等待事件》http://leonarding.blog.51cto.com/6045525/1105414
第三篇 《oracle等待事件3构造一个Direct Path write等待事件和构造一个Log File Sync等待事件》http://leonarding.blog.51cto.com/6045525/1105416

 构造一个DB File Sequential Read等待事件,等待事件需要在v$session_wait10046 trace文件中显示出来,贴出整个演示过程。

db file sequential read 等待事件:是由于数据块顺序读产生的,当数据块(索引块)从磁盘一个一个读到内存中时,在这个过程中oracle会发生“db file sequential read” 等待事件。

块顺序读场景:索引块顺序读

              数据块顺序读

              undo回滚构造一致性读

              磁盘I/O瓶颈

一般来讲如果检索数据时走索引范围扫描INDEX RANGE SCAN 就会发生数据块顺序读的现象,先读取一个索引块,根据索引键值对应ROWID信息在去读ROWID所在的数据块,接下来继续找下一个索引块,在读对应的数据块,就这样一个一个把数据块读取到内存中,这个过程中就会产生“db file sequential read” 等待事件。

下面我们来使用索引块顺序读来产生“db file sequential read

准备环境,原本想利用上面的创建好的表和索引来做的,但一想为了给筒子们一个完整的,详细的,琐碎的,容易验的实验例子,我还是当作重新开始一步一步来搭建环境演示给大家。前提是不是要清理一下环境

LEO1@LEO1> drop table leo1 purge;                                          清理上次的环境

Table dropped.

LEO1@LEO1> create table leo1 as select * from dba_objects;                      创建表

Table created.

LEO1@LEO1> create index idx_leo1 on leo1(object_id);        object_id字段上创建索引,我们要利用索引块顺序读

Index created.

LEO1@LEO1> select table_name,index_name from user_indexes where table_name='LEO1';

TABLE_NAME                     INDEX_NAME

------------------------------ ------------------------------

LEO1                           IDX_LEO1

LEO1@LEO1> execute dbms_stats.gather_table_stats(ownname=>'LEO1',tabname=>'LEO1',cascade=>TRUE);

PL/SQL procedure successfully completed.  为啥每次都需要分析表呢,收集表数据分布情况,看看有没有数据倾斜,在看看索引键值重复率,表和索引存放的位置和大小等,有了一些信息方便CBO更加客观评价执行计划,不做可以嘛?yes -> oracle在必要情况下会进行动态采集操作,显然动态采集只是尽可能抓取一部分样本数据来评估,没有前面一种客观和科学,它的好处在于自动化和方便,无需人工干预。

LEO1@LEO1> set autotrace trace exp                                   启动执行计划

LEO1@LEO1> select owner,object_id,object_name,object_type,status from leo1 where object_id>=100 and object_id<=200;                                                    oracle进行IRS扫描

Execution Plan

----------------------------------------------------------

Plan hash value: 1434365503

----------------------------------------------------------------------------------------

| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |          |   100 |  5200 |     4   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID | LEO1     |   100 |  5200 |     4   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN         | IDX_LEO1 |   100 |       |     2   (0)| 00:00:01 |

----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OBJECT_ID">=100 AND "OBJECT_ID"<=200)        谓词条件是对*操作的说明

我们只看[100,之间的数据,走的是索引范围扫描,就是先读索引块,通过索引键值找到ROWID,在读数据块,这样一个一个读到内存中,就是数据块顺序读类型

LEO1@LEO1> set autotrace off

LEO1@LEO1> select sid,event,total_waits,time_waited from v$session_event;  

SID  EVENT                     TOTAL_WAITS TIME_WAITED

---------- --------------------------------------------------------------------------------

133  db file sequential read        470         122

我们先标记一下等待的次数,如果一会次数增加那么说明成功触发了这个等待事件

LEO1@LEO1> set serveroutput on

LEO1@LEO1> create or replace procedure p2

as

     leo number;

begin

     for i in 1..8000

     loop

         select count(*) into leo from leo1 where object_id>=100 and object_id<=200;

     end loop;

     dbms_output.put_line('successfully');

end;

/

  2    3    4    5    6    7    8    9   10   11  

Procedure created.

创建一个存储过程p2循环8000次(循环的越多执行的时间越长),在循环的过程中我们可以在v$session_wait视图上捕捉到“db file sequential read”select count(*) into leo from leo1 where object_id>=100 and object_id<=200 与 上面的sql执行过程类似只是多了一个汇总过程,也走的是索引范围扫描。

LEO1@LEO1> alter system flush buffer_cache;                  同样也需要先清空data_buffer_cache,原理同上

System altered.

LEO1@LEO1> execute p2;                                   当看到“successfully”表明这个p2执行完毕

successfully

PL/SQL procedure successfully completed.

会话157

LEO1@LEO1> select sid,event,wait_class,p1,p1text,p2,p2text,p3,p3text from v$session_wait where event like '%sequential%';

SID EVENT               WAIT_CLASS    P1  P1TEXT    P2  P2TEXT     P3  P3TEXT

---------- ---------------------------------------------------------------- ----------------- ---------- ---------- ---------------

133 db file scattered read   User I/O       5   file#       2852 block#     1   blocks

在157会话中当对133的存储过程p2执行过程中,马上查看v$session_wait视图,才能捕捉到“db file sequential read”,如果执行完毕了就看不到这个等待事件了,切记切记切记!

参数含义都是一样的,只是p3指单数据块读取,只能显示p3=1,这也符合数据块顺序读的机制

LEO1@LEO1> alter system flush buffer_cache;                 再次清空data_buffer_cache

System altered.

10046 trace文件中显示出来

小提示:当你做实验次数多了时候,会发现要访问的trace文件非常的大在里面找到自己测试sql语句是一件很麻烦的事,这时我们可以选择先清空它在进行测试。

[oracle@leonarding1 trace]$ cd /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/

[oracle@leonarding1 trace]$ ll | grep 6327                              找到6327号文件

-rw-r----- 1 oracle oinstall  187300 Dec 29 01:49 LEO1_ora_6327.trc        

-rw-r----- 1 oracle oinstall    1231 Dec 29 01:49 LEO1_ora_6327.trm

[oracle@leonarding1 trace]$ > LEO1_ora_6327.trc                        清空它既可

[oracle@leonarding1 trace]$ ll | grep 6327                               现在是一个空文件了

-rw-r----- 1 oracle oinstall       0 Dec 29 09:28 LEO1_ora_6327.trc

LEO1@LEO1> alter session set events '10046 trace name context forever,level 12';   启动10046事件

Session altered.

LEO1@LEO1> select count(*) from leo1 where object_id>=100 and object_id<=200;  索引范围扫描

  COUNT(*)

------------------

        94

LEO1@LEO1> alter system flush buffer_cache;                                清空重新抽取数据

System altered.

LEO1@LEO1>select owner,object_id,object_name,object_type,status from leo1 where object_id>=100 and object_id<=200;

LEO1@LEO1> alter system flush buffer_cache;                                再清空

System altered.

LEO1@LEO1> insert into leo1 select * from leo1;         插入数据也会产生顺序读,我们一会看10046事件就知道了

71959 rows created.

LEO1@LEO1> insert into leo1 select * from leo1;

143918 rows created.

LEO1@LEO1> alter session set events '10046 trace name context off';               关闭10046事件

Session altered.

LEO1@LEO1> select name,value from v$diag_info where name='Default Trace File';   当前会话写入trace文件名

NAME            VALUE

--------------------------------------------------------------------------------

Default Trace File   /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_19807.trc

LEO1@LEO1> !vim /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_19807.trc    打开trace文件

====================================================================================================

由于读取的数据量较少,发生的“db file sequential read”也不是很多,你的是不是也这样呢:)

select count(*) from leo1 where object_id>=100 and object_id<=200

END OF STMT

PARSE #2:c=0,e=42,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=6466795,tim=1356745819699276

EXEC #2:c=0,e=67,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=6466795,tim=1356745819699412

WAIT #2: nam='SQL*Net message to client' ela= 11 driver id=1650815232 #bytes=1 p3=0 obj#=0 tim=1356745819699497

WAIT #2: nam='db file sequential read' ela= 26 file#=5 block#=2851 blocks=1 obj#=73718 tim=1356745819699622

WAIT #2: nam='db file sequential read' ela= 16 file#=5 block#=3364 blocks=1 obj#=73718 tim=1356745819699706

====================================================================================================

select owner,object_id,object_name,object_type,status from leo1 where object_id>=100 and object_id<=200

END OF STMT

PARSE #4:c=0,e=108,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1434365503,tim=1356745833882227

EXEC #4:c=0,e=63,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1434365503,tim=1356745833882367

WAIT #4: nam='SQL*Net message to client' ela= 11 driver id=1650815232 #bytes=1 p3=0 obj#=0 tim=1356745833882463

WAIT #4: nam='db file sequential read' ela= 22 file#=5 block#=2851 blocks=1 obj#=73718 tim=1356745833882638

WAIT #4: nam='db file sequential read' ela= 15 file#=5 block#=3364 blocks=1 obj#=73718 tim=1356745833882720

WAIT #4: nam='db file sequential read' ela= 18 file#=5 block#=180 blocks=1 obj#=73717 tim=1356745833883105

====================================================================================================

插入数据操作中,95%会发生大量的“db file sequential read”等待事件,偶尔也能看到“db file scattered read”

因为什么呢?我们想一想插入流程是不是

第一 先从数据文件中把数据块读到内存里在,这时会发生大量的“db file sequential read” 等待事件

第二 再把内存中数据插入到数据文件里

insert into leo1 select * from leo1

END OF STMT

PARSE #3:c=3000,e=2992,p=0,cr=5,cu=0,mis=1,r=0,dep=0,og=1,plh=2716644435,tim=1356745204775114

WAIT #3: nam='db file sequential read' ela= 34 file#=5 block#=182 blocks=1 obj#=73717 tim=1356745204776532

WAIT #3: nam='Disk file operations I/O' ela= 186 FileOperation=2 fileno=3 filetype=2 obj#=73717 tim=1356745204776928

WAIT #3: nam='db file sequential read' ela= 17 file#=5 block#=184 blocks=1 obj#=73717 tim=1356745204777246

WAIT #3: nam='db file sequential read' ela= 25 file#=5 block#=186 blocks=1 obj#=73717 tim=1356745204777889

WAIT #3: nam='db file sequential read' ela= 15 file#=5 block#=188 blocks=1 obj#=73717 tim=1356745204778474

WAIT #3: nam='db file sequential read' ela= 25 file#=5 block#=190 blocks=1 obj#=73717 tim=1356745204779100

。。。。。。。。。。。还有很多不在贴了,节约空间

====================================================================================================

第二次插入为什么,只发生了2次“db file sequential read”,是不是第一次已经把大部分数据加载到内存里啦,第二次的时候就可以直接从内存里往磁盘上插数据了吧,省略了在从磁盘读这步了。

insert into leo1 select * from leo1

END OF STMT

PARSE #4:c=0,e=110,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2716644435,tim=1356745852945838

WAIT #4: nam='db file sequential read' ela= 32 file#=5 block#=4352 blocks=1 obj#=73717 tim=1356745852961373

WAIT #4: nam='db file sequential read' ela= 37 file#=5 block#=4353 blocks=1 obj#=73717 tim=1356745852984158



 

 构造一个Direct Path Read等待事件,等待事件需要在v$session_wait10046 trace文件中显示出来,贴出整个演示过程。

Direct path read 等待事件:发生在“重新读取”的时候,因为排好序数据是一种中间状态,作为计算的中间值存在,不会放在SGA中共享,直接读取到会话私有PGA中,一般是PGA的sort area区

场景:排好序数据会优先放在PGA中,当PGA装满时,就会被写入到磁盘的temp表空间里,当发生“重新读取”的时候,磁盘上的数据不会经过SGA的内存区,而是直接读取到PGA内存区里,在这个过程中将会发生“direct path read”等待事件

LEO1@LEO1> show parameter target

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

archive_lag_target                   integer     0

db_flashback_retention_target        integer     1440

fast_start_io_target                 integer     0

fast_start_mttr_target               integer     0

memory_max_target                big integer 652M

memory_target                    big integer 652M

parallel_servers_target              integer     8

pga_aggregate_target               big integer 0

sga_target                         big integer 0

LEO1@LEO1> set serveroutput on

LEO1@LEO1> select table_name,index_name from user_indexes where table_name='LEO1';

TABLE_NAME                     INDEX_NAME

------------------------------ ------------------------------

LEO1                           IDX_LEO1

我们这次利用一下之前的表leo1,我们已经重做了2次,凡是跟着做的筒子们已经由鱼得水耶,咱们就加快点进度吧。

v$session_wait视图中显示出来

LEO1@LEO1> create or replace procedure p3

as

     leo number;

begin

     for i in 1..1000

     loop

         select count(*) into leo from leo1 order by object_name;

     end loop;

     dbms_output.put_line('successfully');

end;

/

  2    3    4    5    6    7    8    9   10   11  

Procedure created.

创建存储过程p3循环1000次,既然我们要捕捉排好序的数据来产生“direct path read”等待事件,那么我们就要对记录进行order by 操作,这样我们在检索的时候才能看到我们想要的等待事件,其实order by 哪列都可以的。

LEO1@LEO1> execute p3;                                  当看到“successfully”表明这个p3执行完毕

successfully

PL/SQL procedure successfully completed.

会话157

LEO1@LEO1> select sid,event,wait_class,p1,p1text,p2,p2text,p3,p3text from v$session_wait where event like '%direct%';

SID   EVENT           WAIT_CLASS      P1 P1TEXT         P2    P2TEXT         P3  P3TEXT

---------- ---------------------------------------------------------------- ---------- ---------- ---------- ---------- --------------- ---------- ---------------

133   direct path read   User I/O          5 file numbe       1922  first dba        62  block cnt

                                                                                                 133   direct path read   User I/O          5 file numbe       3648  first dba        64  block cnt

                                                                                                  133   direct path read   User I/O          5 file numbe       4226  first dba        62  block cnt

                                                                                                  

我们看到“direct path read”事件发生在5号数据文件的1922  3648  4226号的数据块上,分别从这三个数据块起始开始读取62  64  62 个数据块。

10046 trace文件中显示出来

LEO1@LEO1> alter session set events '10046 trace name context forever,level 12';   启动10046事件

Session altered.

LEO1@LEO1> select count(*) from leo1 order by object_name;                   数据排序

  COUNT(*)

----------------

     71959

LEO1@LEO1> alter session set events '10046 trace name context off';              关闭10046事件

Session altered.

LEO1@LEO1> select name,value from v$diag_info where name='Default Trace File';  当前会话写入trace文件名

NAME            VALUE

--------------------------------------------------------------------------------

Default Trace File   /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_19807.trc

LEO1@LEO1> !vim /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_19807.trc

====================================================================================================

select count(*) from leo1 order by object_name

END OF STMT

PARSE #6:c=1000,e=1320,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=4191104944,tim=1356754783973531

EXEC #6:c=0,e=56,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=4191104944,tim=1356754783973706

WAIT #6: nam='SQL*Net message to client' ela= 12 driver id=1650815232 #bytes=1 p3=0 obj#=7 tim=1356754783973862

WAIT #6: nam='direct path read' ela= 101 file number=5 first dba=179 block cnt=13 obj#=73717 tim=1356754783974411

WAIT #6: nam='direct path read' ela= 103 file number=5 first dba=1457 block cnt=15 obj#=73717 tim=1356754783974600

WAIT #6: nam='direct path read' ela= 103 file number=5 first dba=1473 block cnt=15 obj#=73717 tim=1356754783975005

小结:看只要经过order by排序的检索就会产生“direct path read”等待事件,此时数据是直接读取到PGA内存区的。如果你不先进行排序也可能会出现“direct path read”,但还伴随着db file sequential read和db file scattered read,如果进行排序了那么99%都是direct path read等待事件了。





 本文转自 leonarding151CTO博客,原文链接:http://blog.51cto.com/leonarding/1105414,如需转载请自行联系原作者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值