关于Freelists和Freelist Groups的研究.docx

上传人:b****2 文档编号:1232308 上传时间:2023-04-30 格式:DOCX 页数:22 大小:187.89KB
下载 相关 举报
关于Freelists和Freelist Groups的研究.docx_第1页
第1页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第2页
第2页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第3页
第3页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第4页
第4页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第5页
第5页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第6页
第6页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第7页
第7页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第8页
第8页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第9页
第9页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第10页
第10页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第11页
第11页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第12页
第12页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第13页
第13页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第14页
第14页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第15页
第15页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第16页
第16页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第17页
第17页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第18页
第18页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第19页
第19页 / 共22页
关于Freelists和Freelist Groups的研究.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

关于Freelists和Freelist Groups的研究.docx

《关于Freelists和Freelist Groups的研究.docx》由会员分享,可在线阅读,更多相关《关于Freelists和Freelist Groups的研究.docx(22页珍藏版)》请在冰点文库上搜索。

关于Freelists和Freelist Groups的研究.docx

关于Freelists和FreelistGroups的研究

关于Freelists和FreelistGroups的研究

一.什么是freelists

本文在于探讨Freelists和FreelistGroups的作用,存取机制,争用诊断和优化方法,同时通过理论和测试来推翻一些存在了很久的错误观点。

本文的读者应该具有较深入的Oracle知识,对于一般的开发人员这篇文章可能并没有太多的帮助。

我们知道Oracle数据库的读取单位是数据块(Block),而一个Block是否允许被写入数据是基于一定的空闲度,这就是大家知道的pctfree和pctused存储参数设置。

假设pctfree=10,pctused=40,这就表明当一个Block的空间使用率达到了90%(100-pctfree)时,这个block就不再允许被用于新增数据(insert),而保留下来的这10%的空间则被预留为行更新(update)所可能需要的空间扩展,我们说此时这个block就从freelist上被摘走了(实际上还有另外一种情况,就是当块剩余空间不足以插入一条记录并且该块的使用率已经超过了pctused定义的值并且该块位于freelistheader处时,该块也会从freelist上被摘走,术语称为UNLINK)。

当有数据删除(delete)的时候,只有该block中的数据被删除到一定的程度,该块才会重新被加入到freelists中,而这个程度就是pctused参数定义的数值,如我们这个例子中,只有块中的数据降低到40%以下的时候,该块才被重新允许用于新增数据。

通过上面的描述,可以知道所谓freelists,就是一个指定了所有可以用于insert操作的数据块的列表。

存在在这个列表中的数据块才能用于insert操作,一旦一个数据块无法用于insert(达到了pctfree参数指定的限度)则立刻从这个列表中被摘除。

freelists的作用就在于管理高水位标志(HWM)以下的空闲空间。

注意:

freelists只是管理高水位标志以下的空闲空间,而实际上一个segment可用的空闲空间包括两种类型:

1.已经分配给这个segment但是从来未被使用过的位于高水位标志之上的blocks

2.位于高水位标志之下,被链接在freelists上的blocks

 

至于freelistgroups的概念和作用,在下面的章节适当的地方会解释。

 

二.freelists是否已经过时

随着Oracle9i的推出,对于空闲块的管理变得更加智能和有效率了。

在LMT(LocallyManagedTablespaces)中如果指定了ASSM(AutomaticSegmentSpaceManagement),那么对于任何pctused,freelists,freelistgroups存储参数的指定都将被忽略。

创建ASSM表空间的方法如下:

 

CREATETABLESPACElmtbsbDATAFILE'/u02/oracle/data/lmtbsb01.dbf'SIZE50M

EXTENTMANAGEMENTLOCAL

SEGMENTSPACEMANAGEMENTAUTO;

 

ASSM得益于使用位图(bitmaps)来管理段中的空闲块,至于具体是如何管理的,那又是另外一篇文章了。

就此意义上来说,对于freelists的探讨确实可能已经有些过时了,但是首先并不是所有的数据库现在都已经升级到了Oracle9i,甚至在最需要调整的一些大型应用上往往都由于业务的稳定性而不愿意冒升级到新版本的危险;其次即使是新的应用使用了Oracle9i数据库,如果数据库管理员在创建表空间的时候没有明确指定SEGMENTSPACEMANAGEMENTAUTO,那么默认情况下仍然会使用Freelists和FreelistGroups来管理FreeBlock。

所以,在仍然存在有大量Oracle8i数据库和非自动段空间管理表空间的现在,对于freelists的研究仍然具有很实际的意义,而由于默认的freelists和freelistgroups又都只有1,所以又恰恰是高负载的应用中最需要调整(Tuning)的部分之一。

 

三.freelists存储在哪儿

freelists存储在每个segment的headerblock中,我们可以通过dump来得到更清楚的认识。

dump在研究oracle的内部机制时通常都扮演着很重要的角色。

假设我们创建一个表空间TS_TEST,此表空间是非自动段空间管理的,然后在该表空间中创建T_MANUAL,T_MANUAL_FREE2,T_MANUAL_FREEGROUP2三张表。

这三张表的freelists和freelistgroups设置如下。

 

SQL>selectSEGMENT_NAME,SEGMENT_TYPE,FREELISTS,FREELIST_GROUPSfromUSER_SEGMENTSwhereTABLESPACE_NAME='TS_TEST';

 

SEGMENT_NAMESEGMENT_TYPEFREELISTSFREELIST_GROUPS

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

T_MANUALTABLE11

T_MANUAL_FREE2TABLE21

T_MANUAL_FREEGROUP2TABLE42

 

则可以参照下面的方法对segmentheaderblock进行dump操作。

首先先从数据字典中得到存储这个segment的文件号和此segment的第一个block号(也就是segmentheaderblock)

 

SQL>selectFILE_ID,BLOCK_IDfromdba_extentswheresegment_name='T_MANUAL';

 

FILE_IDBLOCK_ID

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

79

 

使用dump命令转储这个block的内容,转储的结果将保存在初始化参数user_dump_dest指定的目录中。

 

SQL>altersystemdumpdatafile7block9;

 

Systemaltered

 

查看user_dump_dest目录中的相应trace文件,我们可以看到包含如下几行:

frmt:

0x02chkval:

0x0000type:

0x10=DATASEGMENTHEADER-UNLIMITED

表示这个block正是segmentheaderblock。

#blocksinseg.hdr'sfreelists:

2

#blocksbelow:

2

表示位于freelist中的数据块有2个,在高水位标志(HWM)下的数据块也有2个。

SEGLST:

:

flg:

USEDlhd:

0x01c0000altl:

0x01c0000b

由于我们dump的是TS_MANUAL表的headerblock,而这张表的freelists=1,所以在dump文件中看到只有一个seglst,这个freelist被称为segmentfreelist或者masterfreelist,每个segment都至少有一个而且只有一个masterfreelist(当然是在非自动段空间管理类型下)。

flg(flag)表示该freelist是否被使用

lhd(listheader)表示位于该list中的第一个可用block的dba(Datablockaddress)

ltl(listtail)表示位于该list中的最后一个可用block的dba,这个block必定位于HWM之下。

此时我们可以发现freelists只是记录了这个segment中空闲块的第一个块地址和最后一个块地址,在第一个空闲块的块头处(blockheader)记录了它之后的下一个空闲块的地址,而下一个空闲块又记录了再下一个空闲块的地址,由此依次记录,一直到最后一个空闲块。

Oracle通过这种链表的方式实现了freelists对于空闲块的管理。

 

注意:

每次当一个block被加入到freelist中时,该block会被放置在freelist的链表头部。

 

同样我们可以dump第一个空闲块来验证上面的链表说法。

比如在lhd部分记录的dba是0x01c0000a,这是一个16进制的数,首先转化为10进制,于是得到29360138。

然后通过oracle提供的两个函数将块地址转化为可以供我们使用的文件号和块号,以便于我们进行dump操作。

 

SQL>selectdbms_utility.data_block_address_file(29360138)fromdual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

7

 

SQL>selectdbms_utility.data_block_address_block(29360138)fromdual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

10

 

现在我们已经得到第一个空闲块是7号文件的10号块。

用前面提到的转储命令dump这个块的内容,我们可以找到下面的内容:

fnx:

0x1c0000b

表示下一个可用的块地址是0x1c0000b,在我们的例子这个块正好是可用的最后一个块(segmentheaderblock中的lhd部分),我们可以再次dump这个0x1c0000b块,同样查看转储的结果,找到下面的内容:

fnx:

0x0

0x0表示下面没有可用的空闲块了,也就是表明这是freelists中的最后一个空闲块。

 

注意:

你们的测试可能得到跟我不一样的转储内容,这是正常的。

 

四.有多少种freelist

3.masterfreelist或者segmentfreelist

简称为MFL,在segment被创建的时候自动生成的,如果我们在创建segment时没有指定freelists参数,或者指定freelists=1,都是生成这个MFL。

MFL对于每个segment来说有且只有一个(如果指定freelists>1,产生的就是不是MFL,这一点将在processfreelist部分解释)。

MFL相当于一个空闲空间池,当一个segment被创建时的初始化block以及以后动态分配的新block都链接到MFL中,这个池中的所有空闲块是被所有进程共享的,对于该segment有insert操作的所有进程都可能会去读取这个freelist,这样当有多个进程要同时insert数据时,就可能出现在MFL上的争用(MFL在一个时间只能允许一个进程取得空闲块,当然,其实进程从MFL上读取空闲块的操作并不是简单地需要多少就取多少,取得以后就直接向块中插入数据,实际上的过程要更复杂一些,这个过程在"进程请求空闲块的过程"部分会有详细描述)。

由此,推出了freelistgroups的概念,设置freelistgroups参数大于1就是设置了多个MFL,这样就缓解了对于MFL的争用。

有关freelistgroups更详细的内容在"SuperMasterFreelist"部分会有描述。

 

4.processfreelist

如果进程必须直接从MFL中读取空闲块,那么对于MFL的争用由freelistgroups参数解决(设置多个MFL),但是显然还有另外一个思路就是尽量不让进程去直接读取MFL,没有需求自然就无所谓争用。

由此引入了另外一个级别的freelist,这就是processfreelist,简称为PFL。

当我们指定存储参数freelists>1的时候,生成的就是PFL。

我们前面说过MFL是在segment被创建的时候自动生成的,所以无论是不是有PFL,对于每个segment来说都仍然存在1个MFL。

也就是如果我们定义freelists等于2的话,那么在segmentheaderblock中将总共存在3个freelist,其中1个是MFL,另外2个是PFL。

这一点我们同样可以通过dump转储信息来验证。

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

SEGLST:

:

flg:

USEDlhd:

0x01c0008bltl:

0x01c0008b

后面两个freelist既是PFL,而前面一个则是MFL。

顾名思义,既然命名为processfreelist,那么显然位于这个级别的freelist中的空闲块只能被一个进程读取。

想象一下,如果当前系统对于某张表最多同时会有10个进程同时作insert操作,那么我们设置freelists=10,将能尽量满足每个进程都能够使用专属于自己的freelist,无疑通过这样的手段我们缓解了freelist的争用。

一个进程到底会使用哪个PFL,oracle内部的算法是:

(P%NFL)+1

其中P表示DML操作进程的ProcessID,可以从v$process.pid字段中取得。

NFL表示freelists存储参数定义的PFL数量。

可能会有疑问,如果是这样,多个MFL有存在的必要吗?

我们只需要设置多个PFL不就可以了吗?

然而事实并非如此,不过请稍安毋躁,在后面讲解"进程请求空闲块的过程"中会解释这个问题。

 

5.transactionfreelist

在Oracle中事务(transaction)是一个重要的概念,每次DML操作,事务的开始都是自动的,而我们可以通过commit或者rollback来标志一个事务的结束。

一个进程(或者说一个用户会话)有自己的PFL,然后一个进程可能会执行很多的事务,于是又出现了这个级别的freelist,这就是transactionfreelist,简称为TFL。

TFL是动态产生的,只有当DML语句(比如delete或者update)使block占用量降到pctused参数指定值之下时才会生成TFL,一个TFL只属于一个事务,而一个事务也只会有一个TFL,一个事务没有提交之前,此事务的TFL上的空闲块不会被其它事务使用。

但是可以立刻被本事务使用(此时这些空闲块被称为previouslyfreedblocks)。

每个segment最少可以有16个TFL,同时只要有需求就会动态增加TFL数量,除非达到了segmentheaderblocksize的限制。

当没有空间允许新的事务得到自己的TFL时,这个事务就必须等待其它的事务提交并释放TFL。

等待哪个事务的算法是:

(P%NFL)其中P表示DML操作进程的ProcessID,可以从v$process.pid字段中取得。

NFL表示当前的TFL总数量。

通过dump转储数据块信息,我们可以看到类似于下面的内容:

XCTLST:

:

flg:

USEDlhd:

0x01c0008cltl:

0x01c0008axid:

0x0008.01f.000003d2

其中xid表示transactionid,关于transactionid的格式和表示的意义,有兴趣的读者可以查看其它的资料。

 

6.SuperMasterFreelist或者SegmentMasterFreelist

这个级别的freelist只有在设置了多个freelistgroups时才会出现。

当我们设置freelistgroup>1,就会产生freelistgroupblock,这些block紧跟在segmentheaderblock之后,假设我们设置了storage(freelists4freelistgroups2),那么该segment的第一个块是segmentheaderblock,第2,3个块则都是freelistgroupblock。

首先在segmentheaderblock中存在1个freelist,这个freelist就被称为SuperMasterFreelist或者SegmentMasterFreelist。

而在每个freelistgroupblock中又都存着1个MFL,还存在4个PFL,每个freelistgroupblock块的剩余空间则全部留给TFL使用。

在单个instance中进程选择freelistgroup的算法是(P%NFB)+1。

其中P表示DML操作进程的ProcessID,可以从v$process.pid字段中取得。

NFB表示freelistgroups参数定义的FreelistGroups数量。

而在RAC环境中的算法则更加复杂,本文不作讨论了。

查看freelistgroupblock的转储文件可以看到类似于下面的内容:

frmt:

0x02chkval:

0x0000type:

0x16=DATASEGMENTFREELISTBLOCKWITHFREEBLOCKCOUNT

blocksinfreelist=5ccnt=0

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

SEGLST:

:

flg:

USEDlhd:

0x01c00116ltl:

0x01c0011a

SEGLST:

:

flg:

UNUSEDlhd:

0x00000000ltl:

0x00000000

 

五.进程请求空闲块的过程

我们通过对两个事务的描述来说明进程请求空闲块的整个过程。

 

1.事务T1删除了表T中的一些数据,释放了这个segment的block10中的一些空间。

并且使block的已用空间降到pctused参数值以下,因此在segmentheaderblock中产生了一个T1的TFL,而block10被link到这个TFL中。

 

2.事务T2想要插入一些数据到表T中。

但是由于T1没有提交,所以block10并不能被T2使用,而假定T2没有作过释放空间(delete或者update)的操作,所以T2也没有自己的TFL。

 

2.1.T2开始查找自己的PFL,尝试找到可以使用的空闲块(术语称为WALK)。

假设在T2的PFL上有三个block:

block11,12,13,但是都没有足够的空间满足T2的需求。

 

2.2.假定block11的已用空间超过了pctused参数值,而又由于无法满足T2需求,所以从T2的PFL上被摘除(术语称为UNLINK),同时freelistheader变为下一个block,也就是block12(术语称为EXCHANGED),同样block12不满足需求,又exchange到block13,可惜的是block13也同样不满足需求,于是T2的PFL上就没有可使用的空闲块了。

这个步骤的后台思想是当一个块在搜索空闲块的过程中失败,那么就不应该把这个块再放在freelistheader处。

 

注意:

deadblock的出现通常是由于设置了过高的pctused参数导致的。

假设我们设置pctused=90,那么如果由于update等原因使一个block中的数据占用量降低了90%以下,这个block就立刻被重新link到freelist中,但是很可能这一点儿空间根本就不允许insert一条记录,又因为此时的block占用量仍然位于pctused参数值之下,所以即使这个block不满足插入一条记录的条件,也仍然被放置在freelistheader处。

当进程需要freeblock的时候,会先查找这些块(默认最多查找5个块),如果都不满足insert的需求,才尝试提升HWM。

 

 

2.3.T2将PFL上的所有块都检查过,并且发现没有可用的,此时就停止查询PFL

 

2.4.Oracle尝试从MFL中移动空闲块到PFL中(术语称为FreeListsMerge)。

移动的块数是一个常量-5个块。

如果移动成功,那么从2.1步骤重新开始。

注意,此时Oracle不会去检查其它PFL,即使在其它的PFL上可能会有空闲块。

 

2.5.如果上一步中在MFL中没有找到可用的块,此时Oracle尝试从其它已经提交的事务的TFL中获取block。

扫描headerblock中的TFLentries,查看是否有已经提交了并且链接有空闲块的TFL。

如果找到,所有的空闲块都转移到MFL中。

然后从2.4步骤重新开始。

 

2.6.如果上一步失败,Oracle尝试提升高水位标志(bumpupHWM)。

为了减少在segmentheaderblock上的争用,Oracle每次只提升m个block。

m的算法是:

1:

如果HWM<=4并且位于第一个初始化的extent上

5:

未设置隐含参数_bump_highwater_mark_count时

min(_bump_highwater_mark_count*(PFLnumber+1),unusedblocksintheextent):

设置了隐含参数_bump_highwater_mark_count时

 

2.7.如果上一步失败(HWM之上没有分配了但还未使用的block),则分配新的extent,新分配的在只有一个MFL情况下转移到MFL上,然后从2.4步骤重新开始。

在有多个PFL(freelists>1)的情况下,则直接转移到申请空间的进程所拥有的PFL上,然后从2.1步骤重新开始。

 

3.事务T1准备向表T中插入新的记录。

首先,它会检索自己的TFL上是否有空闲空间。

由于block10有可用空间,并且空间满足新纪录的需求,所以block10将会被使用。

 

总结一下上面描述的过程。

当重新insert数据或者发生rowmigration的时候,会从TFLheader处开始使用已经释放了的空闲block。

如果TFL中没有previouslyfreedblocks,那么就从PFL中寻找,因为可能定义了多个freelist,所以到底从哪个freelist中找,算法是前面描述过的(P%NFL)+1。

如果在PFL中找不到或者根本就没有PFL(segment只有一个freelist的情况),那么再从MFL中找。

仍然找不到的话,返回去再查其它会话的TFL,判断其中的事务是否已经commit,如果已经commit了,则把这个TFL的flag标志为unused,同时把位于这个list中的所有block合并到MFL中。

如果经过上面的步骤,在任何一个级别的freelist中都没有找到可用的空闲块,此segment就

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2