近期来
FreeList的重要作用逐渐为Oracle DBA所认识
网上也出现一些相关的讨论
本文以FreeList为线索对Oracle的存储管理的原理进行较深入的探讨
涉及Oracle段区块管理的原理
FreeList算法等
而与FreeList密切相关的一个重用特性HWM
与sql性能密切相关
本文也作了原理分析介绍
在原理探讨的基础上
介绍了常用的存储参数分析方法
并对所涉及的存储优化
HWM的优化和Freelist竞争优化作了说明
缩略语
ASSMauto segement space management
HWMhigh water mark
DBAdata block address
OLTPonline transaction process
OPSoracle parallel server
简介
Oracle的空间管理和存储参数管理是Oracle管理及优化的重要部分FreeList作为Oracle底层存储参数中的核心参数其行为方式对Oracle的存储管理及性能优化有重大影响而现有的Oracle文档对此方面的内容比较缺乏虽然Oracle i已出现了ASSM但是作为深入调优对FreeList认识仍是必要的
近期来FreeList的重要作用逐渐为Oracle DBA所认识网上也出现一些相关的讨论本文以FreeList为线索对Oracle的存储管理的原理进行较深入的探讨涉及Oracle段区块管理的原理FreeList算法等而与FreeList密切相关的一个重用特性HWM与sql性能密切相关本文也作了原理分析介绍在原理探讨的基础上介绍了常用的存储参数分析方法并对所涉及的存储优化HWM的优化和Freelist竞争优化作了说明
这些原理分析和性能优化都建立在探讨的基础上限于篇幅和本人经验可能存在局限偏差或谬误
为了准确文中部分结构和字段的说明直接用英文描述限于篇幅本文不对同样很重要的block结构作更深入的讨论对OPS性能有重要影响的free list group本文也未提及因此本文在单一free list group下讨论对于block的深入讨论free list group的介绍与优化以及PCTUSED和PCTFREE等重要参数的优化请参见参考文献和资料
原理探讨
FreeList作为一个Oracle存储管理的核心参数其行为方式由Oralce内部控制我们一般不需要掌握和控制但是我们可能会遇到这些问题当插入一条记录会插入到那个块中?是使用新块还是插入有数据的老块?段是什么时候扩展的如何扩展的?表中只有一条记录但是作一次select时代价却是上千个块为什么?如果我们从原理上清楚了Oracle的存储管理方式对相关这些问题的解决及性能优化就清晰自然了
Oracle的逻辑储存结构
Oralce的逻辑存储结构按表空间段区块进行管理块是Oracle用来管理存储空间的最基本单元Oracle数据库在进行输入输出操作时都是以块为单位进行逻辑读写操作的区由一系列连续的块组成Oralce在进行空间分配回收和管理时是以区为基本单位的段由多个区组成这些区可以是连续的也可以是不连续的一般情况下一个对象拥有一个段表空间中容纳段和区
在生成段的时候会同时分配初始区(initial extents) 初始区的第一个块就格式化为segment header并被用来记录free list描述信息extents信息HWM信息等
free list概念
free list是一种单向链表用于定位可以接收数据的块在字典管理方式的表空间中Oracle使用free list来管理未分配的存储块Oracle记录了有空闲空间的块用于insert或Update空闲空间来源于两种方式段中所有超过HWM的块这些块已经分配给段了但是还未被使用段中所有在HWM下的且链入了free list的块可以被重用free list具有下列属性
l flag指示free list 被使用()或未使用()
l free list 链的首块的地址DBA(data block address)
l free list 链的尾块的地址DBA
free list 的信息通常保留在segment header中这里给出segment header block dump片段加以说明
nfl = nfb = typ = nxf =
SEG LST:: flg: UNUSED lhd: x ltl: x
SEG LST:: flg: USED lhd: xc ltl: xc
SEG LST:: flg: USED lhd: xc ltl: xc
SEG LST:: flg: UNUSED lhd: x ltl: x
Segment Header:
==> nfl: number of free lists/block
==> nfb: number of free list blocks + segment header
==> typ: block type
==> nxf: number of transaction free lists
Segment List:
==> flg: flag USED or UNUSED the free list
==> lhd: head of free list
==> ltl: tail of free list
在每一个块中都有一个标记flg用来表明块是否链入了 free list链中如果这个标志置上该块中后向指针指向free list链中下一个块的DBA如果当前块是链的最末尾的块该后向指针值为这里给出位于free list上的block dump的片段
Block header dump: xc
Object id on Block? Y
seg/obj: xed csc: xc itc: flg: O typ: DATA
fsl: fnx: xc ver: x
==> Seg/obj Object ID in dictionary
==> csc SCN of last block cleanout
==> itc Number of ITL slots
==> flg O = On freelist = Not on freelist
==> typ = DATA = INDEX
==> fsl ITL TX freelist slot
==> fnx DBA of NEXT block on freelist
举例来说如果有五个块在free list中分别为ABCDE
就会形成segment header>A>B>C>D>E|
同时segment header>E
free list类别
在段中存在类free list 即Master Freelists (MFL) Process Freelists (PrFL) 和 Transaction Freelists
Master Free List(公用空闲空间池):
每一个段中有一个Master free list在段创建的时候自动生成对于每一个段来说都有这样一个空闲空间池对每个进程都是公用的空闲空间就是位于master free list 的块上由于Master free list是公用的因此当多个进程同时插入行到同一个段上master free list竞争使用程度就会增加
Process Free Lists
为了减少Master Free list的竞争问题 引入了另一种free list叫做Process free lists 根据sql命令 CREATE/ALTER 中的参数FREELISTS 创建 这样多个free list 就可以分摊空闲空间的管理以提高OLTP应用作高度并发插入和更新事务时空间分配管理的性能通过指定CREATE TABLE / CLUSTER or INDEX的子句STORAGE的参数FREELISTS 来创建例如: CREATE TABLE flg ( ) STORAGE ( FREELISTS )缺省的FREELISTS为此时不会创建Process free lists当FREELISTS>=时创建Process free lists
进程在使用process free list是根据进程的Oracle PID (Process ID)来选择的公式如下:
select list entry = (PID % NFL) +
NFL : FREELISTS定义的Process free list个数
Transaction Free Lists
当Oracle需要时动态创建一个Transaction Free List 是一种专门给某一个事务使用的free list 每个段至少有个transactions free lists 并且这个值在需要时会增长直到达到Segment Header块的大小限制一个事务只有下面情况下会需要分配一个Tx Free Lists entry: 块中释放空间时(DELETE or UPDATE) 并且还不存在Tx Free Lists entry时
Free list行为
Freelist Link and Unlink 操作
Freelist 按后进先出队列(LIFO) 方式管理也就是说最后被link到freelist的块拥有最先unlink的机会当块中空闲空间增加到大于PCTFREE时块放入freelist中free list中的块可用来作update 或insert 当块中没有足够的空间用于insert操作时并且使用空间大于PCTUSED块就会从free list中移出
在块在DELETE or UPDATE 操作之后如果使用空间落到PCTUSED下块再次link到free list中每次块加入free list时都是link到链表的头部
例如考虑段中有个块编号由到其中有个块在free list上并假设HWM是 (block实际使用DBA编号)
>>>>>|
现在作INSERT 操作需要 bytes空间假设块上空间不足但块上空间可用现在数据插入到块 现在块的剩余空间小于该表的PCTUSED因此块 从free list链表中移出PCTFREE and PCTUSED参数的目的就是用来控制数据块从free list的链表中移入/移出行为的现在free lists象这样
>>>>|
然后在同一事务中作DELETE同一个段的数据使块 和 落到PCTUSED下现在这些块加入到free list链中free list链现在象这样:
>>>>>>|
Transaction Free List 算法
扫描segment Header块中所有的Tx free list检查是否还没有Tx free list entry分配给transaction 如何没有将寻找未使用的entry或已经提交了事务的空的Tx free list如果上述搜索过程失败 新的entry会在segment Header块中Tx free lists区域中开辟如果没有空间来生成 事务就必须等待entry的释放
segment header中的最大free list个数:
Block Size Max # Freelists
K
K
K
k
事务T释放出来的空闲块(DELETE or UPDATE)的使用 :
l 立即被T所重用
l 当T commit后被其它需要空闲块的事务重用过程举例如下:
HMW概念
HIGH WATER MARK代表一个表使用的最大的(top limit)块 中已经提到HIGH WATER MARK 记录在segment header中并且在Oracle插入数据时一般增长个blocks(并非总是个块具体参见中流程图中HMW增长方式)
segment header block中与HWM相关信息说明如下:
EXTENT CONTROL:
Extent Header:: spare: space: #extents: #blocks:
last map x #maps: offset:
Highwater:: xd ext#: blk#: ext size:
#blocks in seg hdrs freelists:
#blocks below:
mapblk x offset:
Unlocked
==> spare: this field is no longer used (old inc# now always )
==> space: this field is no longer used (old ts# now always )
==> #extents: number of extents allocated to segment
==> #blocks: number of blocks allocated to segment
==> last map: address of last extent map block
if extent map is entirely in the segment header
==> #maps: number of extent map block
==> offset: offset to end of extent map
==> HWM dba: address of block at highwater mark
==> ext#: HWM extent number relative to segment
==> blk#: HWM block number within extent
==> ext size: HWM extent size (in blocks)
==> #blocks in seg hdrs freelists: number of blocks in seg hdrs free list
==> #blocks below: number of blocks below HWM
==> mapblk dba: dba of extent map block containing HWM extent
is if HWM is in the segment header
==> offset: offset within extent map block
is the ext# if HWM is in segment header
==> Locked by: if locked by a transaction the xid is displayed
HWM可以说是已经使用过的存储空间和未使用过的存储空间之间的分界线在表使用过程中HWM一直向一个方向移动插入记录时HWM可能会向增加的方向移动但是删除记录时HWM并不会向相反的方向移动参见下图显示了某个数据段中HWM的位置情况
HIGH WATER MARK之所以重要是因为它对全表扫描性能的影响当实施一个全表扫描时Oracle会读取所有HIGH WATER MARK下的块即使它们是空块当HIGH WATER MARK 下有很多unused block时实施全表扫描会增加额外的不必要的I/O它也会在全局共享区中填充很多很多空块
分析方法
存储参数基本上属于oracle internal的东西因此oralce并没有提供很好的手段来分析但是对于DBA来说还是可以通过block dump和DBMS_SPACE等手段来获取部分信息
提取block和free list信息
创建dbms_space使用的存储过程show_space