一.DirectPath Reads 说明
在oracle 11g以前的版本中,如果对大表进行全表扫描,wait event是:db file scattered read;在11g中,如果对大表进行全表扫描,wait event是:direct path read;即在11g中,大表全表扫描是将数据块直接读入会话的pga区域。(具体的查看方法参考后面的示例)。
在11g中,大表全表扫描时数据块不经过sga而直接进pga,这样会造成每次进行大表全表扫描,物理读都是很大,而在10g中,由于全表扫描的数据块在sga中已经存在,所以执行全表扫描时,它的物理读为0。
但是这里主要是oracle在优化策略上的进步,即假定大表频繁全表扫描这种现象,在生产库上不会太多,通过把数据直接读入pga,进而减少了cachebuffer的繁忙交换程度,提高了cachebuffer的使用效率.
direct path read具备更多的优势:
1. 减少了对栓的使用,避免可能的栓争用
2. 物理IO的大小不再取决于buffer_cache中所存在的块;试想某个8个块的extent中1,3,5,7号块在高速缓存中,而2,4,6,8块没有被缓存,传统的方式在读取该extent时将会是对2,4,6,8块进行4次db file sequential read,这是一种十分可怕的状况,其效率往往要比单次读取这个区间的所有8个块还要低得多,虽然Oracle为了避免这种情况总是尽可能的不缓存大表的块(读入后总是放在队列最冷的一端);而direct path read则可以完全避免这类问题,尽可能地单次读入更多的物理块。
direct path read也会引入一些缺点:
1.在直接路径读取某段前需要对该对象进行一次段级的检查点(A segmentcheckpoint).
2.可能导致重复的延迟块清除操作.
该部分引用Maclean 的Blog:
直接路径读取对于延迟块清除的影响
http://www.oracledatabase12g.com/archives/direct-read-impact-on-delayed-block-read.html
MOS 上的说明:High 'direct path read' waits in 11g [ID 793845.1]
There have beenchanges in 11g in the heuristics to choose between direct path reads or readsthrough buffer cache for serial table scans.
In 10g, serialtable scans for "large" tables used to go through cache (by default)which is not the case anymore. In 11g, this decision to read viadirect path or through cache is based on the size of the table, buffer cachesize and various other stats.
Direct path reads are faster than scattered reads andhave less impact on other processes because they avoid latches.
二.相关等待事件说明
http://blog.csdn.net/tianlesoftware/article/details/5807800
2.1 查看等待事件分类情况:
/* Formatted on 2010/8/11 16:08:55 (QP5v5.115.810.9015) */
SELECT wait_class#,
wait_class_id,
wait_class,
COUNT ( * ) AS "count"
FROM v$event_name
GROUP BY wait_class#, wait_class_id, wait_class
ORDER BY wait_class#;
WAIT_CLASS# WAIT_CLASS_IDWAIT_CLASS count
----------- ------------- ------------------------------
0 1893977003Other 717
1 4217450380Application 17
2 3290255840Configuration 24
3 4166625743Administrative 54
4 3875070507Concurrency 32
5 3386400367Commit 2
6 2723168908Idle 94
7 2000153315Network 35
8 1740759767UserI/O 45
9 4108307767SystemI/O 30
10 2396326234Scheduler 7
11 3871361733Cluster 50
12 644977587Queueing 9
2.2 Db file scattered read 等待事件
这个等待事件在实际生产库中经常可以看到,这是一个用户操作引起的等待事件,当用户发出每次I/O需要读取多个数据块这样的SQL 操作时,会产生这个等待事件,最常见的两种情况是全表扫描(FTS: Full Table Scan)和索引快速扫描(IFFS: index fast full scan)。
这个名称中的scattered( 发散),可能会导致很多人认为它是以scattered 的方式来读取数据块的,其实恰恰相反,当发生这种等待事件时,SQL的操作都是顺序地读取数据块的,比如FTS或者IFFS方式(如果忽略需要读取的数据块已经存在内存中的情况)。
这里的scattered指的是读取的数据块在内存中的存放方式,他们被读取到内存中后,是以分散的方式存在在内存中,而不是连续的。
这个等待事件有三个参数:
File#: 要读取的数据块所在数据文件的文件号。
Block#: 要读取的起始数据块号。
Blocks:需要读取的数据块数目。
2.3 Direct path read 等待事件
这个等待事件发生在会话将数据块直接读取到PGA当中,而不是SGA中的情况,这些被读取的数据通常是这个会话私有的数据,所以不需要放到SGA作为共享数据,因为这样做没有意义。这些数据通常是来自与临时段上的数据,比如一个会话中SQL的排序数据,并行执行过程中间产生的数据,以及Hash Join,merge join产生的排序数据,因为这些数据只对当前的会话的SQL操作有意义,所以不需要放到SGA当中。
当发生direct path read等待事件时,意味着磁盘上有大量的临时数据产生,比如排序,并行执行等操作。 或者意味着PGA中空闲空间不足。
这个等待事件有三个参数:
Descriptoraddress: 一个指针,指向当前会话正在等待的一个direct read I/O。
First dba: descriptor address 中最旧的一个I/O数据块地址。
Block cnt: descriptor address上下文中涉及的有效的buffer 数量。
2.4 Direct path write 等待事件
这个等待事件和direct path read 正好相反,是会话将一些数据从PGA中直接写入到磁盘文件上,而不经过SGA。
这种情况通常发生在:
使用临时表空间排序(内存不足)
数据的直接加载(使用append方式加载数据)
并行DML操作。
这个等待事件有三个参数:
Descriptoraddress: 一个指针,指向当前会话正在等待的一个direct I/O.
Firstdba: descriptor address 中最旧的一个I/O数据块地址。
Blockcnt: descriptor address 上下文中涉及的有效地 buffer 数量。
更多链接参考:
db file sequential read
http://sharklove.itpub.net/post/660/279770
db file scattered read
http://sharklove.itpub.net/post/660/279771
direct path write(USER I/0类)
http://sharklove.itpub.net/post/660/279774
direct path read(USER I/0类)
http://sharklove.itpub.net/post/660/279772
三.示例说明
http://blog.csdn.net/tianlesoftware/article/details/7689450
http://blog.csdn.net/tianlesoftware/article/details/5827245
3.1 Oracle 11gR2 示例
SQL> show user
USER is "ANQING"
SQL> create table dave as select rownumrn,rpad('A',600,'Z') rp from dual connect by level <=300000;
Table created.
SQL> set linesize 200 pagesize 1400;
SQL> select count(*) from dave;
COUNT(*)
----------
300000
SQL> col name for a50
SQL> SELECT vm.sid, vs.name, vm.VALUE
2 FROM v$mystat vm, v$sysstatvs
3 WHERE vm.statistic# = vs.statistic#
4 AND vs.name IN
5 ('cleanouts only- consistent read gets',
6 'session logicalreads',
7 'physicalreads',
8 'physical readsdirect',
9 'redo size');
SID NAME VALUE
------------------------------------------------------------ ----------
139 session logical reads 83269
139 physical reads 32505
139 physical reads direct 27273
139 redo size 577392
139 cleanouts only - consistent read gets 4
--查看执行计划:
SQL> set autotrace on
SQL> select count(*) from dave;
COUNT(*)
----------
300000
Execution Plan
----------------------------------------------------------
Plan hash value: 1718719579
-------------------------------------------------------------------
| Id | Operation | Name |Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0| SELECT STATEMENT | | 1 | 7461 (1)| 00:01:30 |
| 1| SORT AGGREGATE | | 1 | | |
| 2| TABLE ACCESS FULL| DAVE | 254K| 7461 (1)| 00:01:30 |
-------------------------------------------------------------------
Note
-----
-dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
27343 consistent gets
27273 physical reads
0 redo size
527 bytes sent via SQL*Net toclient
520 bytes received via SQL*Netfrom client
2 SQL*Net roundtrips to/fromclient
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
3.2 Oracle 10gR2 测试
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise EditionRelease 10.2.0.4.0 - Prod
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Linux: Version 10.2.0.4.0 -Production
NLSRTL Version 10.2.0.4.0 - Production
SQL> create table dave as select rownumrn,rpad('A',600,'Z') rp from dual connect by level <=300000;
Table created.
SQL> col name for a50
SQL> SELECT vm.sid, vs.name, vm.VALUE
2 FROM v$mystat vm, v$sysstatvs
3 WHERE vm.statistic# = vs.statistic#
4 AND vs.name IN
5 ('cleanouts only- consistent read gets',
6 'session logicalreads',
7 'physicalreads',
8 'physical readsdirect',
9 'redo size');
SID NAME VALUE
------------------------------------------------------------ ----------
167 session logical reads 30345
167 physical reads 13
167 physical readsdirect 0
167 redo size 247320
167 cleanouts only - consistent read gets 0
--注意这里的physicalreads direct 为0
SQL> set autotrace on;
seSQL
SQL> select count(*) from dave;
COUNT(*)
----------
300000
Execution Plan
----------------------------------------------------------
Plan hash value: 1718719579
-------------------------------------------------------------------
| Id | Operation | Name |Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0| SELECT STATEMENT | | 1 | 7421 (1)| 00:01:30 |
| 1| SORT AGGREGATE | | 1 | | |
| 2| TABLE ACCESS FULL| DAVE | 280K| 7421 (1)| 00:01:30 |
-------------------------------------------------------------------
Note
-----
-dynamic sampling used for this statement
Statistics
----------------------------------------------------------
28 recursive calls
0 db block gets
27359 consistent gets
27304 physical reads
0 redo size
411 bytes sent via SQL*Net to client
400 bytes received via SQL*Netfrom client
2 SQL*Net roundtrips to/fromclient
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
四.相关的BUG
在Oracle 11g中使用direct path read可以把数据直接读入pga,进而减少了cachebuffer的繁忙交换程度,提高了cachebuffer的使用效率. 但是避开了SGA的过程也导致不能使用sga 的buffer cache。
在MOS上有一篇与Direct Read 相关的bug,MOS如下:KEEP BUFFER POOL Does Not Work for LargeObjects on 11g [ID 1081553.1]
4.1 Symptoms
While doing fulltable scan, Buffer Cache KEEP pool is not being used to read the blocks of a(KEEP) table which size is >10% of DB_KEEP_CACHE_SIZE.
--在Oracle 11gR1中,当我们做全表扫描时,如果需要读取的block大于DB_KEEP_CACHE_SIZE的10%,那么buffercache Keep pool就不会被使用。
Theseblocks are always being read through DIRECT READ, which can causeperformance problem due to non-caching / re-reading of keep object blocks.
--扫描的block会使用direct read,这样会导致性能问题。
4.2 Cause
The problem is caused by Bug8897574 - KEEP BUFFER POOL DOES NOT WORK
The issue is fixed in 12.1 and the fix isincluded in patch set 11.2.0.2 and higher.
--导致上面问题的是因为Bug 8897574,在Oracle 12.1和11.2.0.2中,已经修复了这个bug。
Due to this bug,tables with size >10% of cache size, were being treated as 'largetables' for their reads and this resulted in execution of a newSERIAL_DIRECT_READ path in 11g.
4.3 Solution
Download and apply Patch 8897574 for 11.1.0.7 or 11.2.0.1 for your actualPSU level.
OR
Upgrade to 11.2.0.2 or higher
With the bug fix applied, any object in theKEEP buffer pool, whose size is less than DB_KEEP_CACHE_SIZE, is considered asa small or medium sized object. This will cache the read blocks and avoidsubsequent direct read for these objects .
@ As per development update in the bugreport, to workaround this issue we can set Event10949 at level 1.
-------------------------------------------------------------------------------------------------------
版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!
Skype: tianlesoftware
QQ: tianlesoftware@gmail.com
Email: tianlesoftware@gmail.com
Blog: http://www.tianlesoftware.com
Weibo: http://weibo.com/tianlesoftware
Twitter: http://twitter.com/tianlesoftware
Facebook: http://www.facebook.com/tianlesoftware
Linkedin: http://cn.linkedin.com/in/tianlesoftware
-------加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请----
DBA1 群:62697716(满); DBA2 群:62697977(满) DBA3 群:62697850(满)
DBA 超级群:63306533(满); DBA4 群:83829929 DBA5群: 142216823
DBA6 群:158654907 DBA7 群:172855474 DBA总群:104207940