重庆思庄Oracle、Redhat认证学习论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 3002|回复: 0
打印 上一主题 下一主题

[Oracle] DirectPath Reads 说明

[复制链接]
跳转到指定楼层
楼主
发表于 2020-10-18 18:01:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

传统读取数据的方式是服务器进程通过读取磁盘,然后把数据加载到共享内存中,这样后面的进程就可以通过共享内存访问这些数据,不用再通过缓慢的磁盘读取来 完成。direct path read读取数据块方式,是指服务器进程直接读取数据文件,不经过buffer cache,这种方式读取的数据块会加载到服务器进程的PGA内中当中,不会进入buffer cache中。 11G 之 前的direct path read主要用于并行查询中,此等待事件的三个参数p1,p2,p3分别代表:file#:文件号,first block#:读取的起始块号,block count:以first block为起点,连续读取的物理块数。而从11G之后,direct path read不仅可用于并行查询,在符合某些条件后,串行的全表扫描也可以利用direct path read方式来完成。

在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的使用效率.

Oracle为直接路径读取设置的三个“门槛”:

第 一个阀值:表大小,太小的表从direct path read中的获益太小。但是特别需要引起你的警惕,如果表上存在统计信息,那么ORACLE会采取表的统计信息中记录的block与 _small_table_threshold的设定值来做比较,而不是表的真实大小(dba_segments中记录的值)。这可能导致一些不是你预期 的情况发生。如果你的统计信息与表的真实情况差异很大,那么你应该仔细考虑可能发生什么样的结果。如果你的表没有统计信息,ORACLE会依据表的真实大 小来决定是否进行direct path read。

第二个阀值:脏块阀值,由于direct path read需要出发一个段的检查点,因此脏块太多,刷新脏块可能会导致IO繁忙

第 三个阀值:表在内存里的cache率,如果cache率很高,那么还是走传统路径更快。direct path read的出现,需要让ORACLE公司的开发人员设计一个单独的结构来存储每个表有多少数据是脏数据,有多少数据被cache。不过这个结构目前还并未 暴露给我们查询。在flush buffer cache后,这个结构被清空。(flush shared_pool并不会被清空)

当你预期一个查询应该会走direct path read,但是却走了传统的路径扫描的时候,应该检查是否违背了这三个前置条件中的一个或几个。不过很多时候,当一个查询“应该”走direct path read但是却没有的时候,你往往无能为力,你能在数据库运行过程中修改表的数据的cache比例吗?不能!你能修改表的脏数据的比例吗?往往也不能,通 过修改表的统计信息中的表块数,可以满足第一个条件,但是如果不满足其他两个条件,依然不能有效。你可以通过flush buffer cache来满足后两个条件,但往往在生产环境中不被允许。我曾经在个人微博(新浪微博:魏兴华-DBA)发布过一个关于索引创建走不上direct path read的微博,现在终于想明白了,不满足第三个条件,表被cache的内容需要低于50%。

direct path read具备更多的优势:
1.减少了对栓latch的使用,避免可能的栓争用
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.可能导致重复的延迟块清除操作。
3.如果全表扫描不可避免,而且频繁,会导致IO问题,进而引起宕库。


当然对于小表来说,Oracle允许通过Buffer Cache来进行全表扫描,因为这可能更快,也对性能影响不大。
小表受到隐含参数:_small_table_threshold 影响。如果表大于 5 倍的小表限制,则自动会使用DPR替代FTS。
可以设置初始化参数: _serial_direct_read 来禁用串行直接路径读。

当然,Oracle通过一个内部的限制,来决定执行DPR的阈值。
可以通过设置10949事件屏蔽这个特性,返回到Oracle 11g之前的模式上:

alter session set events '10949 trace name context forever, level 1';

还有一个参数 _very_large_object_threshold 用于设定(MB单位)使用DPR方式的上限,这个参数需要结合10949事件共同发挥作用。
10949 事件设置任何一个级别都将禁用DPR的方式执行FTS,但是仅限于小于 5 倍 BUFFER Cache的数据表,
同时,如果一个表的大小大于 0.8 倍的 _very_large_object_threshold  设置,也会执行DPR。

通过设置隐含参数_serial_direct_read来设置是否启用direct path read,system级别可以由读者自己来完成。
SQL>alter session set "_serial_direct_read"=false;

Oracle通过隐含参数_small_table_threshold来界定大表小表的临界,Oracle认为对于大表执行直接路径读取的意义比较大, 对于小表通过将其缓存可能受益更大。_small_table_threshold的单位为block。默认为db cache size的2%大小,在实例启动过程中动态决定。11GR2之前,表的大小要是_small_table_threshold参数值的5倍才会采取直接路 径读取方式,11GR2后只需要满足_small_table_threshold定义的大小就会采取直接路径读取。

这些限定的目标在于:
对于大表的全表扫描,必须通过Direct Path Read方式执行,以减少对于Buffer Cache的冲击和性能影响。
但是我们可以通过参数调整来决定执行DPR的上限和下限。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 支持支持 反对反对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|重庆思庄Oracle、Redhat认证学习论坛 ( 渝ICP备12004239号-4 )

GMT+8, 2024-11-26 17:30 , Processed in 0.096509 second(s), 20 queries .

重庆思庄学习中心论坛-重庆思庄科技有限公司论坛

© 2001-2020

快速回复 返回顶部 返回列表