我怎样分离Oracle I/O 来使得性能最高? 我是否应该分离数据文件和索引文件? 我是否应该分离redo日志? 这些问题(并且还有更多的)看起来似乎是对于数据库管理员来说的它们在一般程度上很容易解答但是在实际操作中可能是非常难以解决的除非我们检查一下我们的磁盘子系统到底是怎样执行的 我们中的许多人可能立即就不读这篇文章了对自己说这些问题和详细程度只是对于我们的系统管理员或那些控制磁盘管理的人来说的我经常看到两种不同的方式来配置Oracle存储第一种是当架构师要在一个存储数组中分离Oracle对象类型(数据索引重做档案文件等等)时使用Oracle灵活架构(OFAOracles Flexible Architecture)方法第二种方法是建立一个JBOD(Just a Bunch Of Disks简单磁盘捆绑)配置并将所有东西都放到上面这两种方法都缺乏能够最终形成协调的数据库系统的计划和配置它们只是碰运气罢了希望因为遵循了一个预先确定的方法从而一切进行顺利但是这些方法可能在你的环境里不起作用不要依靠于你的系统管理员因为他们自己可能都不知道怎么获取信息而当他们这么做的时候通常是在更高的级别因为他们也不能将这些信息与Oracle堆栈关联起来 所以数据库管理员必须开始从一个纯粹的I/O透视图来了解应用程序将这个信息传递给存储管理员然后一起开发一个配置或改变存储子系统的计划这将用于应用程序混合对于存储OLTP环境的一个重要性能指示器是基于每秒I/O操作次数(IOPS)和延迟(I/O来回的时间)OLAP数据库是你的数据仓库或报表系统并由移动大量的主要做只读的数据来分类对于存储数组一个OLAP环境的性能是基于兆比特位每秒(MBPS)的一个数据库工作负载经常描述为它的应用程序混合了解和将一个应用程序混合转化为一个数据库工作负载对于优化存储系统来说是非常重要的一个OLTP数据库的工作负载是由小的随机I/O来分类的而OLAP是由大型的连续或随机I/O来分类的 对于数据库管理员来说现在该看看你的数据库的内部了你必须想办法获取某种形式的统计信息使你可以在数据库级别分类SQL类型和I/O请求例如Oracle只有很少的表允许提取这个信息举例来说我们可以查询gv$sysstat视图(物理读取总的IO请求——物理读取总的多块请求)来获得系统中小量读取的次数在一段时间内做这个操作用结束时的值减去开始时的值你就很快地获得了那段时间的小量读取的IOPS必须对每一个可用的统计进行这个操作以了解你的数据库所请求的总的IOPS和MBPS这些是你需要获得的相关统计信息基本上大量读写是用来计算MBPS的而小量读写是用来进行IOPS计算的 gv$sysstat(namevalue) TotalReads:physicalreadtotalIOrequests TotalWrites:physicalwritetotalIOrequests LargeReads:physicalreadtotalmultiblockrequests LargeWrites:physicalwritetotalmultiblockrequests TotalBytesRead:physicalreadtotalbytes TotalBytesWritten:physicalwritetotalbytes Tocalculatesmallreads: SmallReads=TotalReadsLargeReads SmallWrites=TotalWritesLargeWrites 使用这些数据使我们可以考虑到我们目前的数据库性能和存储请求从而作出明智的决策数据库可能正在被讨论而实际的I/O请求可能比最优情形下的要低所以可能需要进行调整但是将这些IOPS和MBPS转给存储管理员去评估存储解决方案是否是正确的和是否需要重新配置是数据库管理员的责任这些重新配置可能需要移动数据文件来使用更多的磁盘添加更多的磁盘用于更高的吞吐量或者降低应用程序的IOPS和MBPS是的我们再次回到了应用程序我知道你了解要做什么 下面两个脚本使你可以开始了我花费了很多时间来使它们变得容易使用并提供给你信息使你能够快速了解你的磁盘子系统在过去的时间里执行的怎么样 setechooff setfeedbackoff setheadingoff setlinesize setpagesize setverifyoff settermoutoff columnrptnew_valuerpt selectinstance_name||_||to_char(sysdateYYYYMMDDHHMISS)||_vsysstat_ioworkloadLSTrptfromv$instance; settermouton prompt prompt prompt^^^^^^^^^^^^^ promptReportName:/LST/&&rpt prompt^^^^^^^^^^^^^ spool/LST/&&rpt columnsrnew_valuesr columnswnew_valuesw columnlrnew_valuelr columnlwnew_valuelw columntbrnew_valuetbr columntbwnew_valuetbw settermoutoff SELECT sum(decode(namephysicalreadtotalIOrequestsvalue)decode(namephysicalreadtotalmultiblockrequestsvalue))sr sum(decode(namephysicalwritetotalIOrequestsvalue)decode(namephysicalwritetotalmultiblockrequestsvalue))sw sum(decode(namephysicalreadtotalmultiblockrequestsvalue))lr sum(decode(namephysicalwritetotalmultiblockrequestsvalue))lw sum(decode(namephysicalreadtotalbytesvalue))tbr sum(decode(namephysicalwritetotalbytesvalue))tbw FROMv$sysstat; settermouton prompt prompt prompt^^^^^^^^^^^^ promptFirstSample prompt^^^^^^^^^^^^ promptNumberofSmallReads:&&sr promptNumberofSmallWrites:&&sw promptNumberofLargeReads:&&lr promptNumberofLargeWrites:&&lw promptTotalBytesRead:&&tbr promptTotalBytesWritten:&&tbw prompt prompt promptEntertheamountoftime(inseconds)youwouldlikethisprocesstosleepforsamplingdata prompt^^^^^^^^^^^^^^^^^^ promptSleepTime(secs):&&sleeptime prompt^^^^^^^^^^^^^^^^^^ execDBMS_LOCKSLEEP(&&sleeptime); columnsrnew_valuesr columnswnew_valuesw columnlrnew_valuelr columnlwnew_valuelw columntbrnew_valuetbr columntbwnew_valuetbw settermoutoff SELECT sum(decode(namephysicalreadtotalIOrequestsvalue)decode(namephysicalreadtotalmultiblockrequestsvalue))sr sum(decode(namephysicalwritetotalIOrequestsvalue)decode(namephysicalwritetotalmultiblockrequestsvalue))sw sum(decode(namephysicalreadtotalmultiblockrequestsvalue))lr sum(decode(namephysicalwritetotalmultiblockrequestsvalue))lw sum(decode(namephysicalreadtotalbytesvalue))tbr sum(decode(namephysicalwritetotalbytesvalue))tbw FROMv$sysstat; settermouton prompt prompt prompt^^^^^^^^^^^^^ promptSecondSample prompt^^^^^^^^^^^^^ promptNumberofSmallReads:&&sr promptNumberofSmallWrites:&&sw promptNumberofLargeReads:&&lr promptNumberofLargeWrites:&&lw promptTotalBytesRead:&&tbr promptTotalBytesWritten:&&tbw prompt prompt prompt^^^^^^^^^ promptResults: prompt^^^^^^^^^ columnsrinew_valuesri columnswinew_valueswi columntsinew_valuetsi columnsrpnew_valuesrp columnswpnew_valueswp columnlrinew_valuelri columnlwinew_valuelwi columntlinew_valuetli columnlrpnew_valuelrp columnlwpnew_valuelwp columntrnew_valuetr columntwnew_valuetw columntmnew_valuetm SELECT ROUND((&&sr&&sr)/&&sleeptime)sri ROUND((&&sw&&sw)/&&sleeptime)swi ROUND(((&&sr&&sr)+(&&sw&&sw))/&&sleeptime)tsi ROUND((&&sr&&sr)/DECODE(((&&sr&&sr)+(&&sw&&sw))((&&sr&&sr)+(&&sw&&sw)))*)srp ROUND((&&sw&&sw)/DECODE(((&&sr&&sr)+(&&sw&&sw))((&&sr&&sr)+(&&sw&&sw)))*)swp ROUND((&&lr&&lr)/&&sleeptime)lri ROUND((&&lw&&lw)/&&sleeptime)lwi ROUND(((&&lr&&lr)+(&&lw&&lw))/&&sleeptime)tli ROUND((&&lr&&lr)/DECODE(((&&lr&&lr)+(&&lw&&lw))((&&lr&&lr)+(&&lw&&lw)))*)lrp ROUND((&&lw&&lw)/DECODE(((&&lr&&lr)+(&&lw&&lw))((&&lr&&lr)+(&&lw&&lw)))*)lwp ROUND(((&&tbr&&tbr)/&&sleeptime)/)tr ROUND(((&&tbw&&tbw)/&&sleeptime)/)tw ROUND((((&&tbr&&tbr)+(&&tbw&&tbw))/&&sleeptime)/)tm FROMdual; SELECT SmallReadIOPS=||ROUND((&&sr&&sr)/&&sleeptime)||IOPS SmallWriteIOPS=||ROUND((&&sw&&sw)/&&sleeptime)||IOPS TotalSmallIOPS=||ROUND(((&&sr&&sr)+(&&sw&&sw))/&&sleeptime)||IOPS SmallReadI/O%=||ROUND((&&sr&&sr)/DECODE(((&&sr&&sr)+(&&sw&&sw))((&&sr&&sr)+(&&sw&&sw)))*)||% SmallWriteI/O%=||ROUND((&&sw&&sw)/DECODE(((&&sr&&sr)+(&&sw&&sw))((&&sr&&sr)+(&&sw&&sw)))*)||% LargeReadIOPS=||ROUND((&&lr&&lr)/&&sleeptime)||IOPS LargeWriteIOPS=||ROUND((&&lw&&lw)/&&sleeptime)||IOPS TotalLargeIOPS=||ROUND(((&&lr&&lr)+(&&lw&&lw))/&&sleeptime)||IOPS LargeReadI/O%=||ROUND((&&lr&&lr)/DECODE(((&&lr&&lr)+(&&lw&&lw))((&&lr&&lr)+(&&lw&&lw)))*)||% LargeWriteI/O%=||ROUND((&&lw&&lw)/DECODE(((&&lr&&lr)+(&&lw&&lw))((&&lr&&lr)+(&&lw&&lw)))*)||% TotalRead=||ROUND(((&&tbr&&tbr)/&&sleeptime)/)||MBPS TotalWritten=||ROUND(((&&tbw&&tbw)/&&sleeptime)/)||MBPS TotalMBPS=||ROUND((((&&tbr&&tbr)+(&&tbw&&tbw))/&&sleeptime)/)||MBPS FROMdual ; promptSmallReadIOPS=&&sriIOPS promptSmallWriteIOPS=&&swiIOPS promptTotalSmallIOPS=&&tsiIOPS promptSmallReadI/O%=&&srp% promptSmallWriteI/O%=&&swp% promptLargeReadIOPS=&&lriIOPS promptLargeWriteIOPS=&&lwiIOPS promptTotalLargeIOPS=&&tliIOPS promptLargeReadI/O%=&&lrp% promptLargeWriteI/O%=&&lwp% promptTotalRead=&&trMBPS promptTotalWritten=&&twMBPS promptTotalMBPS=&&tmMBPS spooloff undefinesleeptime 从工作负载库历史记录里获得一个完整的IOPS和MBPS的历史记录并将它绘制出来用于管理这使得你可以看到总的数据库磁盘活动将它与你的磁盘容量相比较记住这些数据是所有磁盘的你通过除以服务数据库请求中的总的磁盘数可以获得平均IOPS/MBPS这是很有用的信息一旦你将结果绘制成图表你就可以看到你的I/O和应用程序的执行在这一天里是怎么样的或者至少确定了峰值时间段在哪 setechooff setfeedbackoff setlinesize setpagesize setverifyoff settermoutoff columnrptnew_valuerpt selectinstance_name||_wrh_sysstat_ioworkload_||LSTrptfromv$instance; settermouton prompt prompt prompt^^^^^^^^^^^^^ promptReportName:/LST/&&rpt prompt^^^^^^^^^^^^^ spool/LST/&&rpt columnsriheadSmall|Read|IOPS columnswiheadSmall|Write|IOPS columntsiheadTotal|Small|IOPS columnsrpheadSmall|Read|I/O% columnswpheadSmall|Write|I/O% columnlriheadLarge|Read|IOPS columnlwiheadLarge|Write|IOPS columntliheadTotal|Large|IOPS columnlrpheadLarge|Read|I/O% columnlwpheadLarge|Write|I/O% columntrheadTotal|Read|MBPS columntwheadTotal|Written|MBPS columntmheadTotal|MBPS columnbegin_timefora columnend_timefora SELECTend_time ROUND(sr/inttime)sri ROUND(sw/inttime)swi ROUND((sr+sw)/inttime)tsi ROUND(sr/DECODE((sr+sw)(sr+sw))*)srp ROUND(sw/DECODE((sr+sw)(sr+sw))*)swp ROUND(lr/inttime)lri ROUND(lw/inttime)lwi ROUND((lr+lw)/inttime)tli ROUND(lr/DECODE((lr+lw)(lr+lw))*)lrp ROUND(lw/DECODE((lr+lw)(lr+lw))*)lwp ROUND((tbr/inttime)/)tr ROUND((tbw/inttime)/)tw ROUND(((tbr+tbw)/inttime)/)tm FROM( SELECTbegsnap_idbeg_idendsnap_idend_id begbegin_interval_timebegend_interval_time endbegin_interval_timebegin_timeendend_interval_timeend_time (extract(dayfrom(endend_interval_timeendbegin_interval_time))*)+ (extract(hourfrom(endend_interval_timeendbegin_interval_time))*)+ (extract(minutefrom(endend_interval_timeendbegin_interval_time))*)+ (extract(secondfrom(endend_interval_timeendbegin_interval_time))*)inttime decode(endstartup_timeendbegin_interval_timeendsr(endsrbegsr))sr decode(endstartup_timeendbegin_interval_timeendsw(endswbegsw))sw decode(endstartup_timeendbegin_interval_timeendlr(endlrbeglr))lr decode(endstartup_timeendbegin_interval_timeendlw(endlwbeglw))lw decode(endstartup_timeendbegin_interval_timeendtbr(endtbrbegtbr))tbr decode(endstartup_timeendbegin_interval_timeendtbw(endtbwbegtbw))tbw FROM (SELECTdba_hist_snapshotsnap_idstartup_timebegin_interval_timeend_interval_time sum(decode(stat_namephysicalreadtotalIOrequestsvalue) decode(stat_namephysicalreadtotalmultiblockrequestsvalue))sr sum(decode(stat_namephysicalwritetotalIOrequestsvalue) decode(stat_namephysicalwritetotalmultiblockrequestsvalue))sw sum(decode(stat_namephysicalreadtotalmultiblockrequestsvalue))lr sum(decode(stat_namephysicalwritetotalmultiblockrequestsvalue))lw sum(decode(stat_namephysicalreadtotalbytesvalue))tbr sum(decode(stat_namephysicalwritetotalbytesvalue))tbw FROMwrh$_sysstatwrh$_stat_namedba_hist_snapshot WHEREwrh$_sysstatstat_id=wrh$_stat_namestat_id ANDwrh$_sysstatsnap_id=dba_hist_snapshotsnap_id groupbydba_hist_snapshotsnap_idstartup_timebegin_interval_timeend_interval_time)beg (SELECTdba_hist_snapshotsnap_idstartup_timebegin_interval_timeend_interval_time sum(decode(stat_namephysicalreadtotalIOrequestsvalue) decode(stat_namephysicalreadtotalmultiblockrequestsvalue))sr sum(decode(stat_namephysicalwritetotalIOrequestsvalue) decode(stat_namephysicalwritetotalmultiblockrequestsvalue))sw sum(decode(stat_namephysicalreadtotalmultiblockrequestsvalue))lr sum(decode(stat_namephysicalwritetotalmultiblockrequestsvalue))lw sum(decode(stat_namephysicalreadtotalbytesvalue))tbr sum(decode(stat_namephysicalwritetotalbytesvalue))tbw FROMwrh$_sysstatwrh$_stat_namedba_hist_snapshot WHEREwrh$_sysstatstat_id=wrh$_stat_namestat_id ANDwrh$_sysstatsnap_id=dba_hist_snapshotsnap_id groupbydba_hist_snapshotsnap_idstartup_timebegin_interval_timeend_interval_time)end WHEREbegsnap_id+=endsnap_id ) orderby / spooloff 从一个纯粹的I/O透视图了解一个应用程序是配置存储的一个关键方面Oracle 具有许多I/O类型需要进行匹配取样和关联到存储在Oracle 中有服务器进程产生的I/O这些服务器进程是由用户多数据库写入检查点活动日志记录工具(它不只是记录更新完成了还要从在线日志读取并通过存档文件过程写到存档文件日志中)产生的还有一些内部的决定规模和I/O频率的I/OOracle是一个非常复杂的包含很多进程的系统不了解你的磁盘I/O形式就几乎不可能做到恰当的配置 |