在Oracle中如何调整I/O相关的等待【转】本文主要介绍的是在出现了I/O竞争等待的时候如何去优化Oracle数据库。对Oracle数据库进行调整优化,基本上最终都可以归结到I/O调整上,因此,了解如何来优化Oracle数据库的I/O对于一个DBA来说就显得至关重要了。一、Oracle数据库I/O相关竞争等待简介当Oracle数据库出现I/O相关的竞争等待的时候,一般来说都会引起Oracle数据库的性能低下,发现数据库存在I/O相关的竞争等待一般可以通过以下的三种方法来查看Oracle数据库是否存在I/O相关的竞争等待:Statpack报告中在Top5WaitEvents部分中主要都是I/O相关的等待事件。数据库的等待事件的SQL语句跟踪中主要都是I/O相关的等待事件的限制。操作系统工具显示存储数据库文件的存储磁盘有非常高的利用率。数据库如果发现存在I/O竞争,那我们就必须要通过各种方法来调整优化Oracle数据库。在调优数据库的过程中,其中一个重要的步骤就是对响应时间的分析,看看数据库消耗的时间究竟是消耗在具体什么上面了。对于Oracle数据库来说,响应时间的分析可以用下面公式来计算:ResponseTime=ServiceTime+WaitTimeServiceTime是指'CPUusedbythissession'的统计时间。WaitTime是指所有消耗在等待事件上的总的时间。如果我们使用性能调整的工具(如statpack)来调整数据库的时候,评测的则是所有响应时间中各个部分的相对影响,并且应该根据消耗的时间的多少来调整影响最严重的部分。因为等待事件有很多,因此我们还需要去判定哪些是真的很重要的等待事件,很多调优工具比如说statpack都是列出最重要的等待事件,statpack工具的报告中的重要的等待事件都是包含在一个叫Top5WaitEvents的部分中。因为这些工具都已经把重要的等待事件全部列出来了,因此就很容易的处理这些已经列出来的等待事件而不必再去首先评估所有响应时间的影响。在某些情况下,ServiceTime会比WaitTime显得更加重要(例如CPU使用率),此时等待事件产生的影响就显得不是那么重要了,重点调整的目标应该放在ServiceTime上。因此,我们应该先比较在Top5WaitEvents部分中的'CPUusedbythissession'所占用的时间,然后直接调整最消耗时间的等待事件。在Oracle9i的release2的版本以后,Top5WaitEvents部分变成了Top5TimedEvents,ServiceTime也由'CPUusedbythissession'变成了'CPUtime'来衡量,这也就意味着可以更加精确的判断在响应时间中的等待事件的影响,从而调整最需要优化的部分。下面举一个例子来具体说明为什么在调整数据库性能的时候必须同时查看ServiceTime和WaitTime,因为如果不同时都查看这两个方面,就往往容易走入调整的误区。Top5WaitEvents~~~~~~~~~~~~~~~~~Wait%TotalEventWaitsTime(cs)WtTime---------------------------------------------------------------------------directpathread9,59015,54686.10dbfilescatteredread6,1051,2626.99latchfree2,0361,0475.80logfilesync107131.73dbfileparallelwrite4069.38上面是一个大约30分钟的statpack收集的信息的Top5WaitEvents部分,如果基于上面给出的列表,我们很容易发现directpathread的wait很高,并且会试图去调整这个等待事件,但是这样做就没有考虑到ServiceTime。我们来看看在这个statpack中关于ServiceTime的统计:StatisticTotalperSecondperTrans-------------------------------------------------------------------------CPUusedbythissession429,648238.7257.4让我们来大致的计算一下响应时间:'WaitTime'=15,546x100%/86.10%=18,056cs'ServiceTime'=429,648cs'ResponseTime'=429,648+18,056=44,7704cs接着来计算一下响应时间中各个部分的比例:CPUtime=95.97%directpathread=3.47%dbfilescatteredread=0.28%latchfree=0.23%logfilesync=0.03%dbfileparallelwrite=0.02%从上面的计算中我们可以明显的看出来,I/O相关的等待事件所消耗的时间在整个响应时间中占的比例并不大,只不过是很小的一部分,而相对来说ServiceTime所消耗的时间远远大于WaitTime,因此,应该直接调整的是ServiceTime(CPU的使用率)而不是I/O相关的等待事件,因此,在调优数据库的时候要尽量的避免走入这种误区。二、Oracle数据库I/O相关竞争等待的处理方法接着来具体看看对于出现的I/O问题处理的一些方法。在使用了statpack这类的工具分析了数据库的响应时间后,如果数据库的性能主要是被一些I/O相关的等待事件所限制住了,那么可以针对这种情况可以采用处理I/O问题的一些方法,下面对这些方法的一些概念和基本原理进行简单的阐述说明。方法一:优化Oracle数据库的SQL语句来减少数据库对I/O的需求:如果数据库没有任何用户的SQL运行的话,一般来说只会产生很少的磁盘I/O或者几乎没有磁盘I/O,基本上来说数据库产生I/O的最终原因都是直接或者间接的由于用户执行SQL语句导致的。这也就意味着我们可以控制单个SQL语句避免其产生大量的I/O来减少整个数据库对磁盘I/O的需求,通过优化SQL语句改变其执行计划以便让其产生尽可能少的I/O。一般典型的存在问题的情况仅仅只是很少的几个SQL语句,但是由于其相应的执行计划不理想,会导致产生大量的物理磁盘I/O,从而使得整个数据库的性能非常之差。因此,让用户执行的SQL语句优化产生比较好的执行计划来减少磁盘I/O是一种非常行之有效的方法。方法二:调整实例的初始化参数来减少数据库的I/O需求:一般来说可以通过两种途径:一种途径是通过内存缓存来减少I/O。数据库的I/O分为两种,一种是实际读取了数据文件的物理I/O,一种是从缓存中读取数据的逻辑I/O,可以通过使用一定数量的内存缓存来减少物理I/O(例如高速缓存区、日志缓存区以及各种排序区等等)。适当的增大高速缓存区,可以有更多的缓存供给数据库的进程使用,从缓存中读取所需要的数据,这样产生的I/O都是逻辑I/O,而不是直接从物理磁盘上读取数据,减少了物理I/O的产生。设置一个适当的排序区,可以减少在排序操作中读取临时表空间数据文件所在磁盘的次数,而尽可能多的使用缓存中的排序区来排序。其他的缓存区的工作原理基本都是一致的,都是通过使用缓存来减少读取物理磁盘的次数来降低I/O。另外一种途径是调整一次读取多个BLOCK的大小,单独的一次多个BLOCK读取的操作的大小是由实例的初始化参数db_file_multiblock_read_count来控制的。如果执行比较大的I/O操作,一次读取的多个BLOCK大小越大,所需要的时间就会越短。例如:操作系统的一次能够传输的最大I/O大小是8M,一次性请求传输50M的数据会比请求5次每次只是请求1M的速度快的多。但是,当一次读取的多个BLOCK的大小超过了操作系统一次能够传输的最大的I/O大小,这个差别就基本不明显了。如一次性传输100M和一次性传输1G的大小在时间上基本上没有什么差别了,效率差不多了。因为整个I/O的所消耗的时间分为I/OSetupTime和I/OTransferTime两个主要部分,I/OSetupTime可以看成是I/O的寻道所消耗的时间,I/OTransferTime可以看成是I/O传输所消耗的时间。当一次读取的多个BLOCK的大小比较小的时候,读取的一定数量的BLOCK就使得读取次数就会比较多,每次I/O读取都要先寻道,并且寻道时间在这个时候所用的时间会占到整个I/O完成时间的绝大部分,导致整个I/O完成所消耗的时间也就会比较多了。而I/O传输一定数量的BLOCK的时间相对固定,不管传输的次数多少,基本上变化不大,因此影响I/O读取时间长短的主要就是取决于I/OSetupTime所花费的时间。因此,在配置数据库初始化参数的时候,根据操作系统的I/O吞吐能力都会设置的一次读取多个BLOCK的大小尽量多,以减少读取I/O的次数。方法三:在操作系统级别上优化I/O:在操作系统级别上优化磁盘的I/O,以提高I/O的吞吐量,如果操作系统支持异步I/O,尽量去使用异步I/O;还可以使用高级文件系统的一些特性,例如直接I/O读取,忽略掉操作系统的文件缓存,也就是我们平时所说的使用裸设备。还有一种可行的方法是增大每次传输的最大I/O大小的限制,以便每次能够传输的I/O尽可能的大。方法四:通过使用RAID、SAN、NAS来平衡数据库的I/O:RAID是RedundentArrayofIndependentDisks的缩写,直译为廉价冗余磁盘阵列,也简称为磁盘阵列。RAID的优点是传输速率高并且可以提供容错功能。在RAID中,可以让很多磁盘驱动器同时传输数据,而这些磁盘驱动器在逻辑上又是一个磁盘驱动器,所以使用RAID可以达到单个磁盘驱动器几倍、几十倍甚至上百倍的速率。因为普通磁盘驱动器无法提供容错功能,如果不包括写在磁盘上的CRC(循环冗余校验)码的话。RAID容错是建立在每个磁盘驱动器的硬件容错功能之上的,所以它提供更高的安全性。RAID分为以下几个级别:RAID0:RAID0并不是真正的RAID结构,没有数据冗余.RAID0连续地分割数据并并行地读/写于多个磁盘上.因此具有很高的数据传输率.但RAID0在提高性能的同时,并没有提供数据可靠性,如果一个磁盘失效,将影响整个数据.因此RAID0不可应用于需要数据高可用性的关键应用。RAID1:RAID1通过数据镜像实现数据冗余,在两对分离的磁盘上产生互为备份的数据.RAID1可以提高读的性能,当原始数据繁忙时,可直接从镜像拷贝中读取数据.RAID1是磁盘阵列中费用最高的,但提供了最高的数据可用率.当一个磁盘失效,系统可以自动地交换到镜像磁盘上,而不需要重组失效的数据。RAID2:从概念上讲,RAID2同RAID3类似,两者都是将数据条块化分布于不同的硬盘上,条块单位为位或字节.然而RAID2使用称为加重平均纠错码的编码技术来提供错误检查及恢复.这种编码技术需要多个磁盘存放检查及恢复信息,使得RAID2技术实施更复杂.因此,在商业环境中很少使用。RAID3:不同于RAID2,RAID3使用单块磁盘存放奇偶校验信息.如果一块磁盘失效,奇偶盘及其他数据盘可以重新产生数据.如果奇偶盘失效,则不影响数据使用.RAID3对于大量的连续数据可提供很好的传输率,但对于随机数据,奇偶盘会成为写操作的瓶颈。RAID4:同RAID2,RAID3一样,RAID4,RAID5也同样将数据条块化并分布于不同的磁盘上,但条块单位为块或记录.RAID4使用一块磁盘作为奇偶校验盘,每次写操作都需要访问奇偶盘,成为写操作的瓶颈.在商业应用中很少使用。RAID5:RAID5没有单独指定的奇偶盘,而是交叉地存取数据及奇偶校验信息于所有磁盘上.在RAID5上,读/写指针可同时对阵列设备进行操作,提供了更高的数据流量.RAID5更适合于小数据块,随机读写的数据