Oracle性能调优之Oracle的FreeList和HWM.docx
《Oracle性能调优之Oracle的FreeList和HWM.docx》由会员分享,可在线阅读,更多相关《Oracle性能调优之Oracle的FreeList和HWM.docx(12页珍藏版)》请在冰豆网上搜索。
Oracle性能调优之Oracle的FreeList和HWM
Oracle性能调优
之FreeList和HWM
海量Oracle资料下载,请收藏
在本文中,我们将以FreeList为线索对Oracle的存储管理的原理进行较深入的讲解,涉及Oracle段区块管理的原理,FreeList算法等。
而与FreeList密切相关的一个重用特性HWM,与sql性能密切相关,本文也作了原理分析介绍。
在原理探讨的基础上,介绍了常用的存储参数分析方法,并对所涉及的存储优化、HWM的优化和Freelist竞争优化作了详细的说明。
缩略语如下:
ASSM:
autosegementspacemanagement
HWM:
highwatermark
DBA:
datablockaddress
OLTP:
onlinetransactionprocess
OPS:
oracleparallelserver
1.前言
Oracle的空间管理和存储参数管理是Oracle管理及优化的重要部分。
FreeList作为Oracle底层存储参数中的核心参数,其行为方式对Oracle的存储管理及性能优化有重大影响,而现有的Oracle文档对此方面的内容比较缺乏。
虽然Oracle9i已出现了ASSM,但是作为深入调优对FreeList认识仍是必要的。
这些原理分析和性能优化都建立在探讨的基础上,限于篇幅和本人经验可能存在局限、偏差或谬误。
为了准确文中部分结构和字段的说明直接用英文描述。
限于篇幅本文不对同样很重要的block结构作更深入的讨论,对OPS性能有重要影响的freelistgroup本文也未提及,因此本文在单一freelistgroup下讨论。
对于block的深入讨论、freelistgroup的介绍与优化以及PCTUSED和PCTFREE等重要参数的优化请参见参考文献和资料。
2.原理探讨
FreeList作为一个Oracle存储管理的核心参数。
其行为方式由Oralce内部控制,我们一般不需要掌握和控制。
但是我们可能会遇到这些问题,当插入一条记录,会插入到那个块中?
是使用新块,还是插入有数据的老块?
段是什么时候扩展的,如何扩展的?
表中只有一条记录,但是作一次select时代价却是上千个块,为什么?
如果我们从原理上清楚了Oracle的存储管理方式,对相关这些问题的解决及性能优化就清晰自然了。
2.1Oracle的逻辑储存结构
Oralce的逻辑存储结构按表空间,段,区,块进行管理。
块是Oracle用来管理存储空间的最基本单元,Oracle数据库在进行输入输出操作时,都是以块为单位进行逻辑读写操作的。
区由一系列连续的块组成,Oralce在进行空间分配、回收和管理时是以区为基本单位的。
段由多个区组成,这些区可以是连续的也可以是不连续的,一般情况下一个对象拥有一个段。
表空间中容纳段和区。
在生成段的时候,会同时分配初始区(initialextents),初始区的第一个块就格式化为segmentheader,并被用来记录freelist描述信息、extents信息,HWM信息等。
2.2freelist概念
freelist是一种单向链表用于定位可以接收数据的块,在字典管理方式的表空间中,Oracle使用freelist来管理未分配的存储块。
Oracle记录了有空闲空间的块用于insert或Update。
空闲空间来源于两种方式:
1.段中所有超过HWM的块,这些块已经分配给段了,但是还未被使用。
2.段中所有在HWM下的且链入了freelist的块,可以被重用。
freelist具有下列属性
flag指示freelist被使用
(1)或未使用(0)
freelist链的首块的地址DBA(datablockaddress)
freelist链的尾块的地址DBA
freelist的信息通常保留在segmentheader中,这里给出segmentheaderblockdump片段加以说明:
nfl=3,nfb=1typ=1nxf=0
SEGLST:
:
flg:
UNUSEDlhd:
0x00000000ltl:
0x00000000
SEGLST:
:
flg:
USEDlhd:
0x03c00233ltl:
0x03c00233
SEGLST:
:
flg:
USEDlhd:
0x03c00234ltl:
0x03c00234
SEGLST:
:
flg:
UNUSEDlhd:
0x00000000ltl:
0x00000000
SegmentHeader:
==>nfl:
numberoffreelists/block
==>nfb:
numberoffreelistblocks+segmentheader
==>typ:
blocktype
==>nxf:
numberoftransactionfreelists
SegmentList:
==>flg:
flagUSEDorUNUSEDthefreelist
==>lhd:
headoffreelist
==>ltl:
tailoffreelist
在每一个块中都有一个标记flg用来表明块是否链入了freelist链中。
如果这个标志置上,该块中后向指针指向freelist链中下一个块的DBA。
如果当前块是链的最末尾的块,该后向指针值为0。
这里给出位于freelist上的blockdump的片段
Blockheaderdump:
0x03c00235
ObjectidonBlock?
Y
seg/obj:
0xe2d8csc:
0x00.6264c61itc:
1flg:
Otyp:
1-DATA
fsl:
1fnx:
0x3c00234ver:
0x01
==>Seg/objObjectIDindictionary
==>cscSCNoflastblockcleanout
==>itcNumberofITLslots
==>flgO=Onfreelist,-=Notonfreelist
==>typ1=DATA2=INDEX
==>fslITLTXfreelistslot
==>fnxDBAofNEXTblockonfreelist
举例来说如果有五个块在freelist中,分别为A,B,C,D,E
就会形成segmentheader->A->B->C->D->E--|
同时segmentheader->E
2.3freelist类别
在段中存在3类freelist,即MasterFreelists(MFL),ProcessFreelists(PrFL),和TransactionFreelists.
2.3.1MasterFreeList(公用空闲空间池):
每一个段中有一个Masterfreelist,在段创建的时候自动生成。
对于每一个段来说都有这样一个空闲空间池,对每个进程都是公用的,空闲空间就是位于masterfreelist的块上。
由于Masterfreelist是公用的,因此当多个进程同时插入行到同一个段上,masterfreelist竞争使用程度就会增加。
2.3.2ProcessFreeLists
为了减少MasterFreelist的竞争问题,引入了另一种freelist叫做Processfreelists,根据sql命令CREATE/ALTER中的参数FREELISTS创建.这样多个freelist就可以分摊空闲空间的管理,以提高OLTP应用作高度并发插入和更新事务时空间分配管理的性能。
通过指定CREATETABLE/CLUSTERorINDEX的子句STORAGE的参数FREELISTS来创建,例如:
CREATETABLEflg(....)...STORAGE(...FREELISTS10...)。
缺省的FREELISTS为1,此时不会创建Processfreelists。
当FREELISTS>=2时,创建Processfreelists。
进程在使用processfreelist是根据进程的OraclePID(ProcessID)来选择的,公式如下:
selectlistentry=(PID%NFL)+1
NFL:
FREELISTS定义的Processfreelist个数
2.3.3TransactionFreeLists
当Oracle需要时动态创建。
一个TransactionFreeList是一种专门给某一个事务使用的freelist.每个段至少有16个transactionsfreelists,并且这个值在需要时会增长,直到达到SegmentHeader块的大小限制。
一个事务只有下面情况下会需要分配一个TxFreeListsentry:
块中释放空间时(DELETEorUPDATE)并且还不存在TxFreeListsentry时。
2.4Freelist行为
2.4.1FreelistLinkandUnlink操作
Freelist按后进先出队列(LIFO)方式管理。
也就是说最后被link到freelist的块拥有最先unlink的机会。
当块中空闲空间增加到大于PCTFREE时,块放入freelist中。
freelist中的块可用来作update或insert。
当块中没有足够的空间用于insert操作时并且使用空间大于PCTUSED,块就会从freelist中移出。
在块在DELETEorUPDATE操作之后,如果使用空间落到PCTUSED下,块再次link到freelist中。
每次块加入freelist时,都是link到链表的头部。
例如:
考虑段中有120个块编号由1到120。
其中有6个块在freelist上并假设HWM是80。
(block实际使用DBA编号)
10->24->45->46->65->80-|
现在作INSERT操作,需要400bytes空间。
假设块10上空间不足,但块24上空间可用。
现在数据插入到块24,现在块24的剩余空间小于该表的PCTUSED。
因此块24从freelist链表中移出。
PCTFREEandPCTUSED参数的目的就是用来控制数据块从freelist的链表中移入/移出行为的。
现在freelists象这样:
10->45->46->65->80-|
然后在同一事务中作DELETE同一个段的数据,使块54和67落到PCTUSED下。
现在这些块加入到freelist链中。
freelist链现在象这样:
67->54->10->45->46->65->80-|
2.4.2TransactionFreeList算法
扫描segmentHeader块中所有的Txfreelist,检查是否还没有Txfreelistentry分配给transaction,如何没有,将寻找未使用的entry或已经提交了事务的空的Txfreelist。
如果上述搜索过程失败,新的entry会在segmentHeader块中Txfreelists区域中开辟。
如果没有空间来生成,事务就必须等待entry的释放。
segmentheader中的最大freelist个数:
BlockSizeMax#Freelists
----------------------------
2K24
4K50
8K101
16k204
事务T1释放出来的空闲块(DELETEorUPDATE)的使用:
l立即被T1所重用
l当T1commit后被其它需要空闲块的事务重用,过程举例如下:
2.5HMW概念
HIGHWATERMARK代表一个表使用的最大的(toplimit)块。
2.1中已经提到HIGHWATERMARK记录在segmentheader中,并且在Oracle插入数据时一般增长5个blocks(并非总是5个块,具体参见2.4.2中流程图中HMW增长方式)。
segmentheaderblock中与HWM相关信息说明如下:
EXTENTCONTROL:
ExtentHeader:
:
spare1:
0space2:
0#extents:
13#blocks:
1429
lastmap0x00000000#maps:
0offset:
4128
Highwater:
:
0x020004d0ext#:
12blk#:
275extsize:
475
#blocksinseg.hdr’sfreelists:
5
#blocksbelow:
1229
mapblk0x00000000offset:
12
Unlocked
==>spare1:
thisfieldisnolongerused(oldinc#,nowalways0)
==>space2:
thisfieldisnolongerused(oldts#,nowalways0)
==>#extents:
numberofextentsallocatedtosegment
==>#blocks:
numberofblocksallocatedtosegment
==>lastmap:
addressoflastextentmapblock
0ifextentmapisentirelyinthesegmentheader
==>#maps:
numberofextentmapblock
==>offset:
offsettoendofextentmap
==>HWMdba:
addressofblockathighwatermark
==>ext#:
HWMextentnumberrelativetosegment
==>blk#:
HWMblocknumberwithinextent
==>extsize:
HWMextentsize(inblocks)
==>#blocksinseg.hdr’sfreelists:
numberofblocksinseg.hdr’sfreelist
==>#blocksbelow:
numberofblocksbelowHWM
==>mapblkdba:
dbaofextentmapblockcontainingHWMextent
is0ifHWMisinthesegmentheader
==>offset:
offsetwithinextentmapblock
istheext#ifHWMisinsegmentheader
==>Lockedby:
iflockedbyatransaction,thexidisdisplayed
HWM可以说是已经使用过的存储空间和未使用过的存储空间之间的分界线。
在表使用过程中,HWM一直向一个方向移动,插入记录时HWM可能会向增加的方向移动,但是删除记录时HWM并不会向相反的方向移动。
HIGHWATERMARK之所以重要是因为它对全表扫描性能的影响。
当实施一个全表扫描时,Oracle会读取所有HIGHWATERMARK下的块即使它们是空块。
当HIGHWATERMARK下有很多unusedblock时实施全表扫描会增加额外的不必要的I/O。
它也会在全局共享区中填充很多很多空块。
3.分析方法
存储参数基本上属于oracleinternal的东西,因此oralce并没有提供很好的手段来分析。
但是对于DBA来说,还是可以通过blockdump和DBMS_SPACE等手段来获取部分信息。
3.1提取block和freelist信息
创建dbms_space使用的存储过程show_space
SQL>
createorreplaceprocedureshow_space
(p_segnameinvarchar2,
p_ownerinvarchar2defaultuser,
p_typeinvarchar2default'TABLE',
p_partitioninvarchar2defaultNULL)
as
l_free_blksnumber;
l_total_blocksnumber;
l_total_bytesnumber;
l_unused_blocksnumber;
l_unused_bytesnumber;
l_LastUsedExtFileIdnumber;
l_LastUsedExtBlockIdnumber;
l_last_used_blocknumber;
procedurep(p_labelinvarchar2,p_numinnumber)
is
begin
dbms_output.put_line(rpad(p_label,40,'.')||p_num);
end;
begin
dbms_space.free_blocks
(segment_owner=>p_owner,
segment_name=>p_segname,
segment_type=>p_type,
partition_name=>p_partition,
freelist_group_id=>0,
free_blks=>l_free_blks);
dbms_space.unused_space
(segment_owner=>p_owner,
segment_name=>p_segname,
segment_type=>p_type,
partition_name=>p_partition,
total_blocks=>l_total_blocks,
total_bytes=>l_total_bytes,
unused_blocks=>l_unused_blocks,
unused_bytes=>l_unused_bytes,
last_used_extent_file_id=>l_LastUsedExtFileId,
last_used_extent_block_id=>l_LastUsedExtBlockId,
last_used_block=>l_last_used_block);
p('FreeBlocks',l_free_blks);
p('TotalBlocks',l_total_blocks);
p('TotalBytes',l_total_bytes);
p('UnusedBlocks',l_unused_blocks);
p('UnusedBytes',l_unused_bytes);
p('LastUsedExtFileId',l_LastUsedExtFileId);
p('LastUsedExtBlockId',l_LastUsedExtBlockId);
p('LastUsedBlock',l_last_used_block);
end;
过程已创建。
SQL>createtablet1(achar(1000))storage(freelists3);
表已创建。
SQL>setserveroutputon;
SQL>execshow_space('T1');
FreeBlocks.............................0<==Numberofblocksonfreelist
TotalBlocks............................5<==Totaldatablocksinsegment
TotalBytes.............................20480<==Totalbytesinsegment
UnusedBlocks...........................4<==Totalunusedblocksinsegment
UnusedBytes............................16384<==Totalunusedbytesinsegment
LastUsedExtFileId....................15<==Fileidoflastusedextent
LastUsedExtBlockId...................562<==Blockidoflastusedextent
LastUsedBlock.........................1<==Lastusedblockinextent
PL/SQL过程已成功完成。
有关show_space的进一步使用技巧可参考文献5。
以下利用上面得到的数据对segmentheaderblock进行dump。
SQL>altersystemdumpdatafile15block562;
在udump/ora10792.trc中
***2004-09-0815:
29:
57.343
Startdumpdatablockstsn:
27file#:
15minblk562maxblk562
buffertsn:
27rdba:
0x03c00232(15/562)
scn:
0x0000.064560e4seq:
0x02flg:
0x00tail:
0x60e41002
frmt:
0x02chkval:
0x0000type:
0x10=DATASEGMENTHEADER-UNLIMITED
ExtentControlHeader
-----------------------------------------------------------------
ExtentHeader:
:
spa