您的位置:首页 > 数据库 > Oracle

Oracle IO问题解析(六)

2012-05-17 14:08 369 查看
3.2数据文件相关的IO事件
数据库系统中的大多数的IO请求都是针对数据文件的。因此大多数情况下,与数据文件相关的IO事件是引起系统IO性能的主要原因。这些事件也是我们文章需要重点介绍的事件。下面分别针对不同事件介绍问题的解决思路。
3.2.1dbfilesequentialread
这个事件是是最常见的IO等待事件。它一般发生在读取单独数据块时,如读取索引数据块或者通过索引访问一个表数据块,另外在读取数据文件头数据块时也会发生dbfilesequentialread等待事件。
当发现这个等待事件成为系统等待事件中的主要事件,我们可以通过一下方法来处理:
3.2.1.1优化TopSQL
从statspack或者awr报告中的“SQLorderedbyReads”部分或者通过V$SQL视图找出系统中的TopSQL,对SQL进行调优以减少IO请求。

当SQL中存在IndexRangeScan时,如果访问的索引的选择性不好就会导致需要访问过多的数据块,这时可以通过建立一个、或强制SQL使用一个已经存在的选择性更好的索引。这样使我们访问更少的数据块来获取到需要的数据。

SQL>selectobject_id,object_name

2fromt_test1

3whereowner='SYS'

4andcreated>sysdate-30;


norowsselected


ExecutionPlan

----------------------------------------------------------

Planhashvalue:4014220762


--------------------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)

|Time|

--------------------------------------------------------------------------------

|0|SELECTSTATEMENT||1|39|11(0)

|00:00:01|

|*1|TABLEACCESSBYINDEXROWID|T_TEST1|1|39|11(0)

|00:00:01|

|*2|INDEXRANGESCAN|T_TEST1_IDX1|576||1(0)

|00:00:01|

--------------------------------------------------------------------------------


PredicateInformation(identifiedbyoperationid):

---------------------------------------------------


1-filter("OWNER"='SYS'AND"CREATED">SYSDATE@!-30)



Statistics

----------------------------------------------------------

0recursivecalls

0dbblockgets

658consistentgets
[/code]
45physicalreads

0redosize

339bytessentviaSQL*Nettoclient

374bytesreceivedviaSQL*Netfromclient

1SQL*Netroundtripsto/fromclient

0sorts(memory)

0sorts(disk)

0rowsprocessed


SQL>createindext_test1_idx2ont_test1(owner,created);


Indexcreated.


SQL>selectobject_id,object_name

2fromt_test1

3whereowner='SYS'

4andcreated>sysdate-30;


norowsselected



ExecutionPlan

----------------------------------------------------------

Planhashvalue:3417015015

---------------------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)

|Time|

---------------------------------------------------------------------------------

|0|SELECTSTATEMENT||49|1911|2(0)

|00:00:01|

|1|TABLEACCESSBYINDEXROWID|T_TEST1|49|1911|2(0)

|00:00:01|

|*2|INDEXRANGESCAN|T_TEST1_IDX2|49||1(0)

|00:00:01|

---------------------------------------------------------------------------------



PredicateInformation(identifiedbyoperationid):

---------------------------------------------------


2-access("OWNER"='SYS'AND"CREATED">SYSDATE@!-30)



Statistics

----------------------------------------------------------

1recursivecalls

0dbblockgets

2consistentgets

1physicalreads

0redosize

339bytessentviaSQL*Nettoclient

374bytesreceivedviaSQL*Netfromclient

1SQL*Netroundtripsto/fromclient

0sorts(memory)

0sorts(disk)

0rowsprocessed


如果索引存在碎片,那每个索引数据块上的索引数据就更少,会导致我们需要访问更多的索引数据块。这时,我们需要考虑重建索引来释放碎片;

判断一个所以是否需要重建,我们介绍一个简单的方法:对一个索引进行结构分析后,如果该索引占用超过了一个数据块,且满足以下条件之一:B-tree树的高度大于3;使用百分比低于75%;数据删除率大于15%,就需要考虑对索引重建:

SQL>analyzeindext_test1_idx1computestatistics;


Indexanalyzed.


SQL>analyzeindext_test1_idx1validatestructure;


Indexanalyzed.


SQL>selectbtree_space,--if>8192(块的大小)

2height,--if>3

3pct_used,--if<75

4del_lf_rows/(decode(lf_rows,0,1,lf_rows))*100asdeleted_pct--if>20%

5fromindex_stats;


BTREE_SPACEHEIGHTPCT_USEDDELETED_PCT

------------------------------------------

8800322890


如果使用的索引的聚簇因子(ClusteringFactor)很大,说明一条索引记录指向多个数据块,在返回结果时需要读取更多的数据块。通过重建表可以降低聚簇因子,因而可以在查找索引时减少表数据块的访问块数。

聚簇因子说明了表数据的物理存储位置相对于一个索引的排序性的符合程度。例如,一个非唯一索引是建立在A字段上的,如果表数据的存储是以A字段的顺序存储的,则索引与数据的关系如下图:



此时,索引的聚簇因子很低,从图上看到,假如我们需要获取A=A2的数据,只需要读取一个数据块就可以了;
相反,如果表数据物理存储顺序和索引顺序相差很大,就会出现下面的情况:



这时该索引的聚簇因子就很大,可以看到,如果需要获取A=A2的数据,我们需要读取4块或更多的数据块。

对索引进行分析后,我们可以从视图DBA_INDEXES中获取到索引的聚簇因子,字段名为Clustoring_Factor。如果一个索引是一张表主要被使用的索引(或者是该表的唯一索引),且它的聚簇因子过高导致IO请求过高的话,我们可以考虑采取以下措施来降低IO:
1)以索引字段的顺序重建表以降低聚簇因子,可以用以下语句重建表(当然,你还需要重建触发器、索引等对象,还可能需要重建、重新编译有关联对象):

CREATEnew_tableASSELECT*FROMold_tableORDERBYA;


2)建立基于索引字段IOT(索引表)。

如果该索引不是表的主要索引,只是被少量语句引用到,按照以上方式处理的话反而可能会使其他使用更加频繁的索引的聚簇因子增大,导致系统性能更差。这时我们可以建立包含返回字段的索引,以避免“TABLEACCESSBYINDEXROWID”。如以下例子:

SQL>setautottrace

SQL>selectstatusfromt_test1

2whereowner='DEMO';


576rowsselected.



ExecutionPlan

----------------------------------------------------------

Planhashvalue:4014220762


--------------------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)

|Time|

--------------------------------------------------------------------------------

|0|SELECTSTATEMENT||576|6336|11(0)

|00:00:01|

|1|TABLEACCESSBYINDEXROWID|T_TEST1|576|6336|11(0)

|00:00:01|

|*2|INDEXRANGESCAN|T_TEST1_IDX1|576||1(0)

|00:00:01|

--------------------------------------------------------------------------------


PredicateInformation(identifiedbyoperationid):

---------------------------------------------------


2-access("OWNER"='DEMO')



Statistics

----------------------------------------------------------

465recursivecalls

0dbblockgets

222consistentgets

43physicalreads

0redosize

8368bytessentviaSQL*Nettoclient

803bytesreceivedviaSQL*Netfromclient

40SQL*Netroundtripsto/fromclient

8sorts(memory)

0sorts(disk)

576rowsprocessed


SQL>createindext_test1_idx3ont_test1(owner,status)computestatistics;

[/code]
Indexcreated.


SQL>selectstatusfromt_test1

2whereowner='DEMO';


576rowsselected.



ExecutionPlan

----------------------------------------------------------

Planhashvalue:2736516725


--------------------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

--------------------------------------------------------------------------------

|0|SELECTSTATEMENT||576|6336|2(0)|00:00:01|

|*1|INDEXRANGESCAN|T_TEST1_IDX3|576|6336|2(0)|00:00:01|

--------------------------------------------------------------------------------


PredicateInformation(identifiedbyoperationid):

---------------------------------------------------


1-access("OWNER"='DEMO')



Statistics

----------------------------------------------------------

1recursivecalls

0dbblockgets
[/code]
43consistentgets
[/code]
3physicalreads
[/code]
0redosize

8152bytessentviaSQL*Nettoclient

803bytesreceivedviaSQL*Netfromclient

40SQL*Netroundtripsto/fromclient

0sorts(memory)

0sorts(disk)

576rowsprocessed


通过分区裁剪(partitionpruning)技术来减少的SQL对数据块的访问。

采用分区裁剪技术,Oracle优化器会先分析FROM和WHERE字句,在建立访问分区列表时将那些不会被访问到的分区排除。例如,我们的表T_TEST1的owner字段的值有“SYS、SYSTEM、XDB、DEMO、TEST”,如果我们按照owner字段建立的是分区表:

CREATETABLEt_test1

(object_idNUMBER(5),

object_nameVARCHAR2(30),

ownerVARCHAR2(20),

createdDATE)

PARTITIONBYLIST(owner)

(

PARTITIONowner_sysVALUES('SYS','SYSTEM'),

PARTITIONowner_xdbVALUES('XDB'),

PARTITIONowner_demoVALUES('DEMO'),

PARTITIONowner_testVALUES('TEST'),

PARTITIONowner_othersVALUES(DEFAULT)

);


则对于以下语句:

selectobject_name

fromt_test1

whereownerin('DEMO','TEST')

andcreated>sysdate-30;

优化器会先将分区owner_sys、owner_xdb、owner_others从分区访问列表中裁剪出去,只访问分区owner_demo和owner_test上的数据或者通过这两个分区上的索引来访问数据。
3.2.1.2处理非SQL导致的IO问题
如果从statspack或者AWR报告中找不到明显产生dbfilesequentialread事件的SQL,则该等待事件可能是由于以下原因导致的:

热点数据文件或磁盘

数据文件所在的磁盘IO负荷过重导致对IO请求反映慢,这时,我们可以通过statspack或AWR报告中的“FileI/OStatistics”部分(或者通过V$FILESTAT视图)来找到热点磁盘:

Statspackreport:
TablespaceFilename

----------------------------------------------------------------------------

AvAvAvAvBufferAvBuf

ReadsReads/sRd(ms)Blks/RdWritesWrites/sWaitsWt(ms)

----------------------------------------------------------------------

AFW_DATA/export/home/icssprd/data/data17/icssprd_afw_data_01

72604.31.038100


AFW_INDX/export/home/icssprd/data/data18/icssprd_afw_indx_01

1,74106.31.02,10400


CSS_AN_DATA/export/home/icssprd/data/data03/icssprd_css_an_data

200,64951.83.224,19210

/export/home/icssprd/data/data04/icssprd_css_an_data

242,46261.63.126,985136.7


CSS_AN_INDX/export/home/icssprd/data/data13/icssprd_css_an_indx

70,78925.01.65,33000


CSS_AUDIT_RESOURCES_DATA/export/home/icssprd/data/data10/icssprd_css_audit_r

2,39400.61.01,78100


CSS_AUDIT_RESOURCES_INDX/export/home/icssprd/data/data11/icssprd_css_audit_r

24804.31.05200


......


视图:
SQL>selectb.name,phyrds,phywrts


2fromV$FILESTATa,V$DATAFILEb


3wherea.file#=b.file#;




NAME


--------------------------------------------------------------------------------


PHYRDSPHYWRTS


--------------------


C:\ORACLE\PRODUCT\10.2.0\ORADATA\EDGAR\DATAFILE\O1_MF_SYSTEM_20TFOB4Q_.DBF


13276711565




C:\ORACLE\PRODUCT\10.2.0\ORADATA\EDGAR\DATAFILE\O1_MF_UNDOTBS1_20TFQP78_.DBF


194319924




C:\ORACLE\PRODUCT\10.2.0\ORADATA\EDGAR\DATAFILE\O1_MF_SYSAUX_20TFSGC6_.DBF


659458100811




......


找到热点数据文件(磁盘)后,我们可以考虑将数据文件转移到性能更高的存储设备上去,或者利用我们上述说的条带化、RAID等存储技术来均衡IO负荷。

热点数据段

从Oracle9.2开始,出现了数据段的概念。每个表和索引都存储在自己的数据段中。我们可以通过视图V$SEGMENT_STATISTICS查找物理读最多的段来找到热点数据段。通过对热点段的分析,考虑采用重建索引、分区表等方式来降低该数据段上的IO负荷。

SQL>selectowner,object_name,tablespace_name,object_type,value


2fromV$SEGMENT_STATISTICS


3wherestatistic_name='physicalreads'


4orderbyvaluedesc;




OWNEROBJECT_NAME


------------------------------------------------------------


TABLESPACE_NAMEOBJECT_TYPEVALUE


----------------------------------------------------------


SYSCONTEXT$


SYSTEMTABLE71




SYSI_CONTEXT


SYSTEMINDEX70




......


另外,我们还可以根据视图v$session_wait中的P1(热点段所在的数据文件号)、P2(发生dbfilesequentialread事件的起始数据块)、P3(数据块的数量,dbfilesequentialread读取数据块数量为1)来定位出热点段:
先找出文件号、起始数据块、数据块数量:

SQL>selectp1"fileid",p2"block_id",p3"block_num"


2fromv$session_wait


3whereevent='dbfilesequentialread';




fileidblock_idblock_num


------------------------------


396448691


然后根据找出的文件号、起始数据块、数据块数量来定位出数据段:

SQL>select


2segment_name"SegmentName",


3segment_type"SegmentType",


4block_id"FirstBlockofSegment",


5block_id+blocks"LastBlockofSegment"


6fromdba_extents


7where&fileid=file_id


8and&block_id>=block_id


9and&block_id<=block_id+blocks;


Entervalueforfileid:396


old7:where&fileid=file_id


new7:where396=file_id


Entervalueforblock_id:44869


old8:and&block_id>=block_id


new8:and44869>=block_id


Entervalueforblock_id:44869


old9:and&block_id<=block_id+blocks


new9:and44869<=block_id+blocks




SegmentName


--------------------------------------------------------------------------------


SegmentTypeFirstBlockofSegmentLastBlockofSegment


-------------------------------------------------------------


CSS_TP_SHMT_QUEUE_ACTIVITY


TABLE4484144873

3.2.1.3调整BufferCache
如果系统中即不存在性能有问题的SQL语句,而且所有磁盘的IO负载也比较均衡(不存在热地磁盘),则我们需要考虑增加BufferCache来降低磁盘IO请求。
在8i,主要是根据缓存命中率(BufferCacheHitRatio)来调整buffercache。当BufferCache调整到一定大小,对命中率没什么影响了时,就没有必要在增大BufferCache了。可以通过以下语句来查看BufferCache命中率:

SQL>select1-(physical_reads)/(consistent_gets+db_block_gets)


2fromv$buffer_pool_statistics;




1-(PHYSICAL_READS)/(CONSISTENT_GETS+DB_BLOCK_GETS)


--------------------------------------------------


.95628981


在9i中,可以利用statspackreport中的BufferCache建议部分来调整BufferCache的大小。

BufferPoolAdvisoryforDB:ICSSPRDInstance:icssprdEndSnap:259


->Onlyrowswithestimatedphysicalreads>0aredisplayed


->orderedbyBlockSize,BuffersForEstimate




SizeforSizeBuffersforEstPhysicalEstimated


PEstimate(M)FactrEstimateReadFactorPhysicalReads


-------------------------------------------------------------------


D304.137,7159.185,928,235,496


D608.275,4306.884,443,709,043


D912.3113,1455.733,699,496,220


D1,216.4150,8603.872,502,670,372


D1,520.5188,5752.321,499,049,228


D1,824.6226,2901.701,099,326,418


D2,128.7264,0051.41912,042,579


D2,432.8301,7201.22790,925,174


D2,736.9339,4351.09703,357,378


D2,9921.0371,1951.00645,905,997


D3,0401.0377,1500.99636,992,420


D3,3441.1414,8650.90583,996,250


D3,6481.2452,5800.84542,063,246


D3,9521.3490,2950.79508,261,496


D4,2561.4528,0100.74480,472,150


D4,5601.5565,7250.71455,533,563


D4,8641.6603,4400.67434,743,759


D5,1681.7641,1550.64416,285,837


D5,4721.8678,8700.62400,208,242


D5,7761.9716,5850.60385,785,401


D6,0802.0754,3000.57365,597,932


-------------------------------------------------------------


这里,EstPhysicalReadFactor是估算的从磁盘物理读取次数与从buffercache中读取的次数的比值。从意见估算的图表中,当BufferCache的增长对该因子影响不大时,则说明无需在增大BufferCache,我们就可以去相应临界点的大小作为BufferCache的大小。上述例子中,我们可以考虑设置BufferCache大小为2992M。

在Oracle10g中,引入了新的内存管理特性——自动共享内存管理(AutomaticSharedMemoryManagementASMM)。基于这一特性,oracle能够自动根据当前的负荷计算出最优的BufferCache大小。关于ASMM,可以参见文章《Oracle内存全面分析》的SGA_TARGET部分。

我们可以采用多尺寸缓冲池技术将热点数据段(表或索引)KEEP在缓冲池中:

SQL>altertablet_test1storage(buffer_poolkeep);




Tablealtered.


关于多尺寸缓冲的更多内容,可以参考文章《Oracle内存全面分析》的“多缓冲池部分”部分。
3.2.1.4Housekeep历史数据
对于一些被频繁访问到的大表,我们需要定期对其做housekeep,将一些不用的、老的数据从表中移除,以减少访问的数据块。定期对含有时间轴的Transaction表做housekeep是降低IO负载的重要措施。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Oracle 文章 file