3.2.3      db file parallel read
首先,不要被该事件名称所误导——它和并行DML或者并行查询都无关。当从多个数据文件并行读取数据到非联系的内存(PGA、Buffer Cache)缓冲中时,会发生该等待事件。它通常发生在Recovery操作或者利用缓冲预提取(Buffer Prefetching)从数据文件并行读取数据时。
我们可以通过以下语句找出发生db file parallel read等待事件的数据文件和数据块:
 
select p1 "fileid", p2 "block_id", p3 "requests"
  from v$session_wait
 where event = 'db file parallel read';
 
优化该等待事件的手段可以参考优化db file sequential read等待事件中非SQL优化方法部分。
3.2.4      direct path read & direct path read (lob)
当直接读取(Direct Read)数据到PGA(而不是到Buffer Cache)中去时,会发生Direct Path Read等待事件。对Lob数据的直接读有一个单独的等待事件——direct path read (lob)。
当Oracle设置支持异步IO时,进程可以在提交IO请求后继续做其他操作,并且在稍后再提取IO请求返回的结果,在提取结果时就产生了direct path read等待事件。
在没有启用异步IO时,IO请求在完成之前会被阻塞,但在执行IO操作时并不会产生等待事件。进程稍后回来提取那些已经读取到的IO数据,这时尽管能够很快返回,但仍然会显示direct path read等待事件。
和其他IO等待事件不同的是,对Direct Path Read等待事件要注意以下两点:
 
  • 等待次数并不等于IO请求次数;
  • 统计(如statspack报告中)得出的Direct Path Read的等待时间并不一定代表该事件引起的真正等待时间。
 
事件中的P1、P2、P3参数分别代表:
P1:发生等待事件的数据块所在文件号;
P2:发生等待事件的数据块号;
P3:等待事件涉及的连续数据块数量。
 
直接读(Direct Read)请求一般发生在以下几种情况:
 
  • 磁盘排序IO(Sort Area不足时,排序用到的临时数据会被写到临时表空间上去,当读取这些数据时就使用直接读);
  • 并行查询;
  • 预读取(当一个进程认为某个数据块将很快被用到而发出IO请求时)
  • Hash Join(Hash Area不足)
  • IO负载系统中,服务进程处理缓存的速度比系统IO返回数据到缓存的速度更快时
 
通过视图V$SESSION_EVENT我们可以找出当前产生等待的会话,再根据会话中正在进行的操作确定导致等待的原因。针对不同的原因,我们可以采取不同的措施减少Direct Path Read等待事件。
3.2.4.1 磁盘排序
首先我们可以考虑优化语句以减少排序操作。排序一般是由以下操作引起的:
 
o        Order By;
o        JOIN;
o        UNION;
o        Group By;
o        聚合操作;
o        Select unique;
o        Select distinct;
 
可以尝试在语句中减少没必要的上述操作来避免排序操作。另外,创建索引也会引起排序操作。在专业模式(Dedicated)下,排序所占用的内存是从PGA中分配出来的一块区域,叫Sort Area,由参数sort_area_size控制其大小;在MTS中,排序区是从Large Pool中分配的。当sort area大小无法满足排序操作要求时,就会占用临时表空间来存放排序数据,因而产生Direct Path Read等待事件。我们可以通过适当增加该参数来减少磁盘排序操作。
这个参数可以在系统范围或会话范围进行修改。对于一些需要做大量排序操作而且又比较独立的会话(如Create Index),我们可以在会话级别为其设置比较大的Sort Area以满足排序需要:
 
SQL> alter session set sort_area_size = 10000000;
 
Session altered.
 
该参数大小一般推荐设置为1~3M。在9i之后,不推荐设置该参数,我们可以通过设置PGA_AGGREGATE_TARGET进行PGA内存自动管理(设置WORKAREA_SIZE_POLICY为TRUE)。对于PGA_AGGREGATE_TARGET的大小设置,可以参考文章《Oracle内存全面分析》中的PGA_AGGREGATE_TARGET部分。
此外,我们还可以通过以下语句来查找系统中存在磁盘排序的会话及其语句:
 
SELECT a.sid,a.value, b.name, d.sql_text from
V$SESSTAT a, V$STATNAME b, V$SESSION c, V$SQLAREA d
WHERE a.statistic#=b.statistic#
AND b.name = 'sorts (disk)'
and a.sid = c.sid
and c.SQL_ADDRESS = d.ADDRESS(+)
and c.SQL_HASH_VALUE = d.HASH_VALUE(+)
and value > 0
ORDER BY 2 desc,1;
3.2.4.2 并行查询
当设置表的并行度非常高时,优化器可能就对表进行并行全表扫描,这时会引起Direct Path Read等待。
在使用并行查询前需要慎重考虑,因为并行查询尽管能教师程序的响应时间,但是会消耗比较多的资源。对于低配置的数据库服务器不建议使用并行特性。此外,需要确认并行度的设置要与IO系统的配置相符(建议并行度为2~4 * CPU数)。在10g中,可以考虑使用ASM。
对于表的并行度,我们不建议直接用ALERT修改表的物理并行度:
 
ALTER TABLE t_test1 PARALLEL DEGREE 16;
 
而是推荐针对特定语句使用提示来设置表的并行度:
 
SQL> SELECT /*+ FULL(T) PARALLEL(T, 4)*/ object_name FROM t_test1 t;
 
47582 rows selected.
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2467664162
 
--------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time
|    TQ  |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |          | 47582 |  1068K|    42   (3)| 00:00:01
|        |      |            |
|   1 |  PX COORDINATOR      |          |       |       |            |
|        |      |            |
|   2 |   PX SEND QC (RANDOM)| :TQ10000 | 47582 |  1068K|    42   (3)| 00:00:01
|  Q1,00 | P->S | QC (RAND)  |
|   3 |    PX BLOCK ITERATOR |          | 47582 |  1068K|    42   (3)| 00:00:01
|  Q1,00 | PCWC |            |
|   4 |     TABLE ACCESS FULL| T_TEST1  | 47582 |  1068K|    42   (3)| 00:00:01
|  Q1,00 | PCWP |            |
--------------------------------------------------------------------------------
3.2.4.3 Hash Join
Hash Area是用于hash join的内存区域。Hash Area过小会引起Direct Path Read等待。当WORKAREA_SIZE_POLICY为FALSE时,可以考虑增加hash_area_size的大小(建议为sort_area_size大小的1.5倍);当WORKAREA_SIZE_POLICY为TRUE时,可以考虑增加PGA_AGGREGATE_TARGET大小。
3.2.4.4 Direct path read (lob)
为了减少LOB的读写时间,通常我们会设置LOB的存储参数NOCACHE,这时读取LOB时会引起Direct Path Read (lob)等待事件。但当我们发现Direct path read (lob) 引起了IO性能问题,就需要考虑将那些被经常读取的LOB字段设置为CACHE。另外,如果操作系统的文件系统有足够的Buffer Cache时可以考虑将LOB数据段存储在文件系统上。
3.2.4.5 其他优化措施
当内存资源不足、IO读取数据到内存效率远远低于内存中数据被处理的效率时,会引起Direct Path Read等待事件。作为对上述处理措施的补充,增加内存(PGA)、在确保操作系统支持AIO情况下设置DISK_ASYNCH_IO为TRUE以支持异步IO、采用效率更高的存储设备都能帮助我们减少Direct Path Read等待。
3.2.5      direct path write & direct path write (lob)
 
直接写(Direct Path Write)允许一个会话先将IO写请求放入一个队列中,让操作系统去处理IO,而自身可以继续处理其他操作。当会话需要知道写操作是否完成(如会话需要一块空闲的缓存块或者会话需要确认内存中所有写操作都被flush到磁盘了),会话就会等待写操作完成从而产生Direct Path Write等待事件。Direct Path Write (lob) 是在对LOB数据段(NOCACHE)直接写时产生的等待事件。
在没有启用异步IO时,IO写请求在完成之前会被阻塞,但在执行IO写操作时并不会产生等待事件。进程稍后回来提取那些已经完成的IO操作数据,这时尽管能够很快返回,但仍然会显示direct path write等待事件。
和Direct Path Read等待事件相似,对Direct Path Write等待事件也要注意以下两点:
 
  • 等待次数并不等于IO请求次数;
  • 统计(如statspack报告中)得出的Direct Path Write的等待时间并不一定代表该事件引起的真正等待时间。
 
事件中的P1、P2、P3参数分别代表:
P1:发生等待事件的数据块所在文件号;
P2:发生等待事件的数据块号;
P3:等待事件涉及的连续数据块数量。
 
直接写请求一般发生在以下几种情况:
 
  • 直接数据载入操作(如CTAS、SQL*Loader设置Direct选项等);
  • 并行DML操作;
  • 磁盘排序(排序内存空间不足,数据写入磁盘);
  • 载入NOCACHE数据段;
 
对Direct Path Write的优化处理措施基本上和Direct Path Write类似。