转载:http://www.dbtan.com/2010/04/direct-path-readwrite.html

direct path read/write (直接路径读/写):

直接路径读(direct path read)通常发生在Oracle直接读数据到进程PGA时,这个读取不需要经过SGA。直接路径读等待事件的3个参数分别是file number(指绝对文件号)、first dba、block cnt数量。在Oracle 10g/11g中,这个等待事件被归于User I/O一类。

db file sequential read、db file scattered read、direct path read是常见的集中数据读方式,下图简要描述了这3种方式的读取示意。

这类读取通常在以下情况被使用:
·磁盘排序IO操作;
·并行查询从属进程;
·预读操作。

最为常见的是第一种情况。在DSS系统中,存在大量的direct path read是很正常的,但是在OLTP系统中,通常显著的直接路径读(direct path read)都意味着系统应用存在问题,从而导致大量的磁盘排序读取操作。

直接路径写(direct paht write)通常发生在Oracle直接从PGA写数据到数据文件或临时文件,这个写操作可以绕过SGA。直接路径写等待事件的3个参数分别是:file number(指绝对文件号)、first dba和block cnt数量,在Oracle 10g/11g中,这个等待事件同direct path read一样被归于User I/O一类。

这类写入操作通常在以下情况被使用:
·直接路径加载;
·并行DML操作;
·磁盘排序;
·对未缓存的“LOB”段的写入,随后会记录为direct path write(lob)等待。

最为常见的直接路径写,多数因为磁盘排序导致。对于这一写入等待,我们应该找到I/O操作最为频繁的数据文件(如果有过多的排序操作,很有可能就是临时文件),分散负载,加快其写入操作。

1. 磁盘排序诊断:
如果系统存在过多的磁盘排序,会导致临时表空间操作频繁,对于这种情况,可以考虑为不同用户分配不同的临时表空间,使用多个临时文件,写入不同磁盘或者裸设备,从而降低竞争,提高性能;对于Oracle 8i的数据库,应该考虑使用本地管理(Local)的临时表空间,而不是字典(dictionary)管理。

对于这种情况,在Oracle 9i之前,可以适当增加sort_area_size的大小;从Oracle 9i开始,可以适当增大pga_aggregate_target,以缩减磁盘排序对于磁盘的写入,从而提高系统及应用响应。但是通常应该及时检查应用,确认是否因为应用问题导致了过度排序,从而根本上解决问题。

2. 并行查询导致性能问题:
有时候在应用系统中,不正确的使用并行查询也会导致应用问题。Statspack的Top 5时间事件输出显示direct path read消耗了较高的等待时,而内存排序率很高甚至是100%(In-memory Sort %:100.00)显然这里的Direct Path Read并不是由于排序引发的,注意到另外一个等待事件(KJC: Wait for msg sends to complete)和并行有关,所以初步判断这里的direct path read可能和并行有关。

注:在Statspack的报告中,存在一个性能指标,称为内存排序率(In-memory Sort Ratio),用于衡量系统的排序操作,这个指标就是由两个统计信息sorts (disk)和sorts (memory)得出:
    In-memory Sort Ratio = sorts (memory) / [sorts (disk) + sorts (memory)]

进一步检查Statspack报告中的SQL部分,发现大量并行查询改写出来的SQL,这些SQL通过内部提示(Hints)固化其执行路径。

在很多情况下,并行也许并不是最好的选择,如果表并不大,并行反而会降低其执行速度。

通过查询dba_tables字典表可以获得degree并行度的记录,并行度大于1的数据表在查询时会启用并行,但是注意事实还会有所不同,degree字段的类型及长度是VARCHAR2(10)。所以注意,当使用类似查询时,可能无法获得返回值:

sys@CCDB> select table_name from dba_tables where degree = '1' or degree = 'DEFAULT';
no rows selected

我们看一下degree以及instances的记录方式:

sys@CCDB> select degree,length(degree) from dba_tables group by degree;
DEGREE          LENGTH(DEGREE)
--------------- --------------
         1                  10
sys@CCDB> select instances,length(instances) from dba_tables group by instances;
INSTANCES       LENGTH(INSTANCES)
--------------- -----------------
         1                     10
         0                     10

degreee和instances实际上记录了10个字符,左端用空格补齐。在dba_tables的创建语句中,可以找到根本原因,以下是这两个字段的定义来源:

lpad(decode(t.degree, 32767, 'DEFAULT', nvl(t.degree,1)),10),
    lpad(decode(t.instances, 32767, 'DEFAULT', nvl(t.instances,1)),10),

而需要注意的是,如果degree设置为DEFAULT,则默认数据库会对该表启用并行。

最后找到相关的SQL,从AUTOTRACE可以看到这些SQL的执行计划,查看涉及数据表的并行度,注意是否有被设置为DEFAULT的表。

将表的并行度修改为1后,问题得以解决:

alter table <table_name> parallel 1;

这个问题给我们的启示是:并行并不总是能够到来性能提升。

3. 磁盘排序与临时文件:
在Oracle 10g/11g中,为了区分特定的对于临时文件的直接读写操作,Oracle对direct path read/write进行了分离,将这类操作分列出来:

sys@CCDB> select event#,name,wait_class
  2  from v$event_name
  3  where name like 'direct%';
    EVENT# NAME                      WAIT_CLASS
---------- ------------------------- ---------------
       177 direct path read          User I/O
       178 direct path read temp     User I/O
       179 direct path write         User I/O
       180 direct path write temp    User I/O

可以看到,现在的direct path read/write temp就是单指对于临时文件的直接读写操作。结合Oracle 10g的一些特性,来进一步研究一下直接路径读/写与临时文件。
首先在一个session中执行一个能够引发磁盘排序的查询:

tq@CCDB> select sid from v$mystat where rownum <2;
       SID
----------
      1066
tq@CCDB> select a.table_name,b.object_name,b.object_type
  2  from t1 a,t2 b
  3  where a.table_name = b.object_name
  4  order by b.object_name,b.object_type;

在另外sessoin查询相应等待事件:

tq@CCDB> select event,p1text,p1,p2text,p2,p3text,p3
  2  from v$session_wait_history
  3  where sid = 1066;
EVENT                    P1TEXT             P1 P2TEXT            P2 P3TEXT            P3
------------------------ ------------- ------- ------------ ------- ------------ -------
direct path read temp    file number       201 first dba     313512 block cnt         31
direct path read temp    file number       201 first dba     313481 block cnt         31
direct path read temp    file number       201 first dba     386887 block cnt         31
direct path read temp    file number       201 first dba     317736 block cnt         31
direct path read temp    file number       201 first dba     317193 block cnt         31
direct path read temp    file number       201 first dba     316646 block cnt         31
direct path read temp    file number       201 first dba     316134 block cnt         31
direct path read temp    file number       201 first dba     315622 block cnt         31
direct path read temp    file number       201 first dba     315079 block cnt         31
direct path read temp    file number       201 first dba     314567 block cnt         31
10 rows selected.

从以上输出可以看到最近10次等待,direct path read temp就是这个查询引起的磁盘排序。注意这里的file number为201。而实际上,通过v$tempfile来查询,临时文件的文件号仅为1:

tq@CCDB> select file#,name from v$tempfile;
     FILE# NAME
---------- -----------------------------------------
         1 /oracle/oradata/ccdb/ccdb/temp01.dbf

如果通过10046事件跟踪,也可以获得类似的结果:

WAIT #3: nam='direct path write temp' ela= 1 file number=201 first dba=437862 block cnt=31 obj#=112141 tim=1270780
330976998
WAIT #3: nam='direct path write temp' ela= 1 file number=201 first dba=437416 block cnt=31 obj#=112141 tim=1270780
330977070
WAIT #3: nam='direct path read temp' ela= 7 file number=201 first dba=438471 block cnt=31 obj#=112141 tim=12707803
30982214
WAIT #3: nam='direct path read temp' ela= 4 file number=201 first dba=438502 block cnt=31 obj#=112141 tim=12707803
30983765
WAIT #3: nam='direct path read temp' ela= 8 file number=201 first dba=387015 block cnt=31 obj#=112141 tim=12707803
30993872

在Oracle文档中,file#被定义为绝对文件号(The Absolute File Number)。这里的原因何在呢?研究这个问题要先研究一下v$tempseg_usage这个视图,可以从这个视图出发动手研究一下这个对象究竟来自何方。

查询dba_objects视图,发现v$tempseg_usage原来是一个同义词。

sys@CCDB> select object_type from dba_objects where object_name = 'V$TEMPSEG_USAGE'; 
OBJECT_TYPE
-------------------
SYNONYM

再追本溯源原来v$tempseg_usage是v_$sort_usage的同义词,也就是和v$sort_usage同源。从Oracle 9i开始,Oracle将v$sort_usage视图从文档中移除了,因为这个名称有所歧义,容易使人误解仅记录排序内容,所以v$tempseg_usage视图被引入,用于记录临时段的使用情况:

sys@CCDB> select * from dba_synonyms where synonym_name = 'V$TEMPSEG_USAGE';
OWNER      SYNONYM_NAME         TABLE_OWNER     TABLE_NAME      DB_LINK
---------- -------------------- --------------- --------------- ----------
PUBLIC     V$TEMPSEG_USAGE      SYS             V_$SORT_USAGE

如果再进一步,可以看到这个视图的构建语句:

sys@CCDB> select view_definition from v$fixed_view_definition 
  2  where view_name = 'GV$SORT_USAGE';                  
VIEW_DEFINITION
--------------------------------------------------------------------------------
select x$ktsso.inst_id, username, username, ktssoses, ktssosno, prev_sql_addr, p
rev_hash_value, prev_sql_id, ktssotsn, decode(ktssocnt, 0, 'PERMANENT', 1, 'TEMP
ORARY'), decode(ktssosegt, 1, 'SORT', 2, 'HASH', 3, 'DATA', 4, 'INDEX', 5, 'LOB_
DATA', 6, 'LOB_INDEX' , 'UNDEFINED'), ktssofno, ktssobno, ktssoexts, ktssoblks,
ktssorfno from x$ktsso, v$session where ktssoses = v$session.saddr and ktssosno
= v$session.serial#

格式化一下,v$sort_usage的创建语句如下:

SELECT   x$ktsso.inst_id,username,username,ktssoses,ktssosno,
         prev_sql_addr,prev_hash_value,prev_sql_id,ktssotsn,
         DECODE (ktssocnt,
                 0,'PERMANENT',
                 1,'TEMPORARY'),
         DECODE (ktssosegt,
                 1, 'SORT',
                 2, 'HASH',
                 3, 'DATA',
                 4, 'INDEX',
                 5, 'LOB_DATA',
                 6, 'LOB_INDEX',
                 'UNDEFINED'),
         ktssofno,ktssobno,
         ktssoexts,ktssoblks,ktssorfno
  FROM   x$ktsso, v$session
WHERE   ktssoses = v$session.saddr AND ktssosno = v$session.serial#;

注意到在Oracle文档中对v$sort_usage字段SEGFILE#的定义为:

SEGFILE#    NUMBER        File number of initial extent

在视图中,这个字段来自x$ktsso.ktssofno,也就是说这个字段实际上代表的是绝对文件号。那么这个绝对文件号如何与临时文件关联呢?能否与v$tempfile中的file#字段关联呢?

再来看一下v$tempfile的来源,v$tempfile由如下语句创建:

sys@CCDB> select view_definition from v$fixed_view_definition
  2  where view_name = 'GV$TEMPFILE';
VIEW_DEFINITION
--------------------------------------------------------------------------------
select tf.inst_id, tf.tfnum, to_number(tf.tfcrc_scn), to_date(tf.tfcrc_tim,'MM/D
D/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'), tf.tftsn, tf.tfrfn, decode(bitand(tf
.tfsta, 2),0,'OFFLINE',2,'ONLINE','UNKNOWN'), decode(bitand(tf.tfsta, 12), 0,'DI
SABLED',4, 'READ ONLY', 12, 'READ WRITE',
                           'UNKNOWN'), fh.fhtmpfsz*tf.tfbsz, fh.fhtmpfsz,  tf.tf
csz*tf.tfbsz,tf.tfbsz, fn.fnnam  from x$kcctf tf, x$kccfn fn, x$kcvfhtmp fh  whe
re fn.fnfno=tf.tfnum and fn.fnfno=fh.htmpxfil and tf.tffnh=fn.fnnum  and tf.tfdu
p!=0 and bitand(tf.tfsta, 32) <> 32  and fn.fntyp=7 and fn.fnnam is not null

格式化v$tempfile如下:

SELECT   tf.inst_id,tf.tfnum,TO_NUMBER (tf.tfcrc_scn),
         TO_DATE (tf.tfcrc_tim,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'),
         tf.tftsn,tf.tfrfn,
         DECODE (BITAND (tf.tfsta, 2), 0, 'OFFLINE', 2, 'ONLINE', 'UNKNOWN'),
         DECODE (BITAND (tf.tfsta, 12),
                 0, 'DISABLED',
                 4, 'READ ONLY',
                 12, 'READ WRITE',
                 'UNKNOWN'),
         fh.fhtmpfsz * tf.tfbsz,fh.fhtmpfsz,tf.tfcsz * tf.tfbsz,tf.tfbsz,fn.fnnam
  FROM   x$kcctf tf, x$kccfn fn, x$kcvfhtmp fh
WHERE       fn.fnfno = tf.tfnum
         AND fn.fnfno = fh.htmpxfil
         AND tf.tffnh = fn.fnnum
         AND tf.tfdup != 0
         AND BITAND (tf.tfsta, 32) <> 32
         AND fn.fntyp = 7
         AND fn.fnnam IS NOT NULL;

考察x$kcctf底层表,注意到TFAFN(Temp File Absolute File Number)在这里存在

sys@CCDB> desc x$kcctf
Name             Null?    Type
---------------- -------- ----------------
ADDR                      RAW(8)
INDX                      NUMBER
INST_ID                   NUMBER
TFNUM                     NUMBER
TFAFN                     NUMBER
TFCSZ                     NUMBER
TFBSZ                     NUMBER
TFSTA                     NUMBER
TFCRC_SCN                 VARCHAR2(16)
TFCRC_TIM                 VARCHAR2(20)
TFFNH                     NUMBER
TFFNT                     NUMBER
TFDUP                     NUMBER
TFTSN                     NUMBER
TFTSI                     NUMBER
TFRFN                     NUMBER
TFPFT                     NUMBER
TFMSZ                     NUMBER
TFNSZ                     NUMBER

而这个字段在构建v$tempfile时并未出现,所以不能通过v$sort_usage和v$tempfile直接关联绝对文件号。可以简单构建一个排序段使用,然后来继续研究一下:

sys@CCDB> select username,segtype,     340361          1          1

看到这里的SEGFILE#=201,而在v$tempfile是找不到这个信息的:

sys@CCDB> select           1          3 ONLINE      443520

但是可以从x$kcctf中获得这些信息,v$tempfile.file#实际上来自x$kcctf.tfnum,是临时文件的文件号;而绝对文件号是x$kcctf.tfafn,这个字段才可以与v$sort_usage.segfile#关联

sys@CCDB> select indx,               2560

再进一步可以知道,实际上,为了分离临时文件号和数据文件号,Oracle对临时文件的编号以db_files为起点,所以临时文件的绝对文件号应该等于db_files+file#

db_files参数的缺省值为200:

sys@CCDB> show parameter db_files
NAME          TYPE           VALUE
------------- -------------- -----------
db_files      integer        200
sys@CCDB> select file#,name from v$tempfile;
     FILE# NAME
---------- ---------------------------------------------
         1 /oracle/oradata/ccdb/ccdb/temp01.dbf

所以在Oracle文档中v$tempfile.file#被定义为The absolute file number是不确切的。

- The End -

direct path read/write (直接路径读/写)的更多相关文章

  1. Oracle 11g新特性direct path read引发的系统停运故障诊断处理

    黎俊杰 | 2016-07-28 14:37 声明:部分表名为了脱敏而用XX代替 1.故障现象 (1)一个业务系统输入用户名与密码后无法进入首页,表现为一直在运行等待,运行缓慢 (2)整个系统无法正常 ...

  2. [转帖]direct path read直接路径读

    direct path read直接路径读 http://blog.itpub.net/12679300/viewspace-1188072/ 原创 Oracle 作者:wzq609 时间:2014- ...

  3. 深入解析direct path read (转)

    文章转自:http://www.itpub.net/thread-1815281-1-1.html 传统读取数据的方式是服务器进程通过读取磁盘,然后把数据加载到共享内存中,这样后面的进程就可以通过共享 ...

  4. oracle 11G direct path read 很美也很伤人

    direct path read在11g中,全表扫描可能使用direct path read方式,绕过buffer cache,这样的全表扫描就是物理读了. 在10g中,都是通过gc buffer来读 ...

  5. [20171120]11G关闭直接路径读.txt

    [20171120]11G关闭直接路径读.txt --//今天做filesystemio_options参数测试时,遇到一个关于直接路径读的问题.--//如果看以前的博客介绍,设置"_ser ...

  6. oracle 11g禁用和强制direct path read

    一般在混合型环境中,大表在进行全表扫描或者走并行的时候一般会出现direct path read等待事件,如果在OLTP或者纯粹的DSS环境中,出现大量的direct path read直接路径读取, ...

  7. oracle 11G direct path read 非常美也非常伤人

    direct path read 在11g中,全表扫描可能使用direct path read方式,绕过buffer cache,这种全表扫描就是物理读了. 在10g中,都是通过gc buffer来读 ...

  8. Oracle收集对表收集统计信息导致全表扫描直接路径读?

    direct path read深入解析 前言 最近碰到一件很奇葩的事情,因为某条SQL执行缓慢,原因是走了笛卡尔(两组大数据结果集),而且笛卡尔还是NL的一个部分,要循环31M次. 很容易发现是统计 ...

  9. direct path read

    在11g中,全表扫描可能使用direct path read方式,绕过buffer cache,这样的全表扫描就是物理读了. 在10g中,都是通过gc buffer来读的,所以不存在direct pa ...

随机推荐

  1. linux C 内存分配(~道的光芒四射~)

    总结一下C语言中基本的内存分配,加深对内存管理的印象,一步一步走山路~~~~~~~~ 1.  程序和进程 问题:程序和进程各是什么? 程序 只是一段可以执行的代码文件,通俗讲在 linux 上就是一个 ...

  2. OK335xS Linux Qt make: icpc: Command not found

    OK335xS Linux Qt make: icpc: Command not found 一.出错现象: make: icpc: Command not found make: *** [main ...

  3. nmap扫描时的2个小经验

    http://pnig0s1992.blog.51cto.com/393390/367558/ 1.我肉鸡的环境是Windows XP sp3,在使用nmap扫描外网的时候,提示我 pcap_open ...

  4. BZOJ3514: Codechef MARCH14 GERALD07加强版【LCT】【主席树】【思维】

    Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...

  5. elastic job简单用法

    public class JobMain { //配置注册中心 private ZookeeperConfiguration zkConfig = new ZookeeperConfiguration ...

  6. [UE4]虚幻4的智能指针

    虚幻自己实现了一套智能指针系统,为了跨平台. 指针: 占用8个字节,4个字节的Object指针,4字节的引用计数控制器的指针, 引用计数控制器需要12字节, 一个C++的Object指针4字节,一个共 ...

  7. Spring学习--静态工厂方法、实例工厂方法创建 Bean

    通过调用静态工厂方法创建 bean: 调用静态工厂方法创建 bean 是将对象创建的过程封装到静态方法中 , 当客户端需要对象时 , 只需要简单地调用静态方法 , 而不需要关心创建对象的细节. 要声明 ...

  8. 创意:Soap一款新型的触摸式家用智能路由器

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/iefreer/article/details/34808749 Soap简单介绍 这里的Soap不是 ...

  9. 解决python2安装MySQL-python模块报错

    今天电脑重装系统,所有软件都重装一遍,MySQLdb模块一直装不好,纠结了好久,终于解决,方法分享给大家. MySQLdb模块安装: 1.下载MySQL-pyhon模块,网站为:https://pyp ...

  10. Codelf 变量取名

    Codelf 变量取名 可以看到别的变量是怎么命名的,站在巨人的肩膀上.