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 readselect 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中,一般是PGAsort 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 readdb file scattered read,如果进行排序了那么99%都是direct path read等待事件了。





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

相关文章
|
SQL Oracle 关系型数据库
Polar DB-O (兼容 Oracle 语法版本)和Polar DB PostgreSQL 版本概述(二)
Polar DB-O (兼容 Oracle 语法版本)和Polar DB PostgreSQL 版本概述(二)
1734 0
|
Oracle 前端开发 Java
Oracle优化11-10046事件
Oracle优化11-10046事件
89 0
|
SQL Oracle 关系型数据库
Oracle优化12-10053事件
Oracle优化12-10053事件
100 0
|
Oracle 关系型数据库 数据库
Oracle-等待事件解读
Oracle-等待事件解读
96 0
|
SQL Oracle 关系型数据库
Oracle 等待事件研究:SQL*Net break/reset to client
SQL*Net break/reset to client事件是一个容易被误解的事件,这个事件看起来和网络有关,但实际上大多数情况下这个事件与网络无关。
571 0
Oracle 等待事件研究:SQL*Net break/reset to client
|
SQL 存储 监控
Oracle中的SQL_TRACE是什么?诊断事件是什么?常用的10046及10053诊断事件的区别是什么?
Oracle中的SQL_TRACE是什么?诊断事件是什么?常用的10046及10053诊断事件的区别是什么?
507 0
|
Oracle 关系型数据库 数据库
❤️Oracle TOP5事件解读,性能优化必备技能❤️
❤️Oracle TOP5事件解读,性能优化必备技能❤️
311 0
❤️Oracle TOP5事件解读,性能优化必备技能❤️
|
SQL Oracle 关系型数据库
如何快速批量导入非Oracle DB格式的数据--sqlloader
在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法
350 0
如何快速批量导入非Oracle DB格式的数据--sqlloader