前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【循序渐进Oracle】Oracle段空间管理技术

【循序渐进Oracle】Oracle段空间管理技术

作者头像
数据和云
发布2018-03-07 11:05:52
1.7K0
发布2018-03-07 11:05:52
举报
文章被收录于专栏:数据和云

在Oracle数据库内部,对象空间是以段的形式(Segment)存在和管理的,通过不同的段类型Oracle将段区分开来,在Oracle 9i中,主要的段类型有:

当一个段被创建时,区间(Extent)就被分配,随着后续的不断使用,一个段的空间可以以区为单位不断扩展。

前面提到Extent的管理技术是通过字典或本地的方式进行的,那么当Extent被分配给Segment,这个空间又是如何管理的呢?“SEGMENT SPACEMANAGEMENT AUTO”这个语句就是定义的段空间管理方式。

Oracle的段空间管理方式主要有两种,一种是手工段空间管理(Manual Segment Space Management,缩写为MSSM),由于这种方式使用自由列表来管理段空间,所以也被称为自由列表管理方式(Freelist Mangement,缩写为FLM),一种就是Oracle 9i带来的全新的自动段空间管理(Auto Segment Space Management,缩写为ASSM)。

手工段空间管理(Manual Segment Space Management)

MSSM管理方式是Oracle最初实现的一种段空间管理技术。前面提到,区间(Extent)是Oracle的最小空间分配单元,而Block是Oracle的最小IO操作单元,也就是说,Oracle以区间为单位将空间分配给对象段,而段内则是以Block为单位进行空间使用和管理的。

这个段空间管理在Oracle9i之前是通过手工段空间管理技术实现的,这种技术的具体实现方式是通过在段头(Segment Header)分配自由列表(freelist)来管理Block的使用,简单一点,可以把自由列表想象成一个数据表,Oracle依赖一系列的算法通过向自由列表中加入或移出Block来实现段空间管理。

当创建对象时(如数据表)可以定义freelist的数量,对于数据表缺省的freelist为1,可以通过dba_segments查询得到这些数据:

当向一个对象中插入数据时,Oracle首先在该对象的freelist上寻找可用于插入数据的Block,当一个Block用完之后,就会从freelist上摘除,当这个Block上由于数据删除等空间释放后,可以再次回到freelist上来,而这主要是通过存储参数PCTFREE和PCTUSED来实现。

当向一个对象中插入数据时,假设PCTFREE=20,PCTUSED=40,这就表明当一个Block的空间使用率达到了80%时,这个block就不再允许被用于新增数据(insert),而保留下来的这20%的空间则被预留为行更新(update)所可能需要的空间扩展,此时这个Block就从freelist上被移除;当这个Block中有数据被删除(delete)时,空间不断被释放,当空间使用低于PCTUSED参数设置时(此处即为40%),这个数据块块才会重新被加入到freelists中,加入freelist后这个Block又可以被插入新的数据,如图所示。

通过以上的描述可以看到,如果一个段的操作非常频繁,那么很多用户就会同时请求访问freelist,并对freelist进行修改,这就很容易产生竞争。对于表来说,缺省的freelist为1,这就很容易引发竞争,虽然可以通过增加freelist的方法缓解这种竞争,但是我们已经看到这种管理方式存在的缺陷。所以从Oracle9i开始,Oracle推出了ASSM的管理方式。

接下来可以通过DUMP的方式来转储数据块的头信息,发现freelist的设置等:

检查trace文件就可以发现如下信息:

这里的hdr'sfreelists就是指freelist里面的数据块数量,本例的表中,freelist中有76个空闲数据块。有兴趣的读者可以进行一点深入研究,这里不再过多介绍。

自动段空间管理(Auto Segment Space Management)

在Oracle 9i中,Oracle引入了自动段空间管理(ASSM)技术,在ASSM中,原有的freelist被位图所取代,通过位图能够迅速有效地管理存储扩展和剩余区块(freeblock),因此能够改善段存储管理的本质。

在ASSM管理下,insert通过扫描位图来查找可用的block,即使block的可用空间低于PCTFREE,也不会从位图中摘除,因此PCTUSED参数将不再需要;而PCTFREE参数,仍然需要它来指示需要保留多少空间给后续的update导致的行数据增长使用。至于freelists和freelist groups参数在ASSM中都无效了。

新的管理机制用位图数组来跟踪或管理每个分配到对象的块,而每个块有多少剩余空间是根据位图的状态来确定的,如>75%、50%~75%、25%~50%和<25%,也就是说位图其实采用了4个状态位来代替以前的PCTUSED,什么时候该利用该数据块则由设定的PCTFREE来确定。

使用ASSM的一个巨大优势是,位图数组肯定能够减轻缓冲区忙等待(buffer busy wait)的负担,这个问题在Oracle 9i以前的版本里曾经是一个严重的问题。在没有多个自由列表的时候,每个Oracle段通过在段头保留一个数据块用于自由列表(假定只有一个freelist),自由列表用来管理对象所使用的剩余区块,并为新数据行提供数据块。可以想象,当多个事务并发请求空间时,竞争将会出现。

有了ASSM之后,Oracle宣称显著地提高了DML并发操作的性能,因为位图数组的不同部分可以被同时使用,这样就消除了寻找剩余空间的串行化。根据Oracle的测试结果,使用位图数组会显著地消除所有对段头的竞争,还能获得超快的并发插入性能。以下是ASSM表空间中一个数据文件的头部的结构。

删除前面创建的测试表空间:

SQL> drop tablespace eygle including contents and datafiles; Tablespace dropped.

重新创建一个ASSM管理的表空间:

然后创建一个对象:

通过图5-4来看一下ASSM的管理机制,首先前2个数据块为数据文件头,3~8个数据块为区位图块,接下来的第9个块和第10个块就是ASSM位图块。

一级位图块用于管理具体数据块的使用,来看一下第9个Block的内容:

SQL> alter system dump datafile 3 block 9; System altered.

转储文件内容为:

注意到这个位图管理了16个Block,地址范围从0x00c00009开始(也就是第9个数据块),其中前3个Block(0~2)用于存储元数据,其余用来存储数据,FULL状态表示块已经用完。这就是第一级位图块(FIRST LEVELBITMAP BLOCK)。

由于这个位图块只能管理16个Block,如果这个对象的空间超过这个值,那么Oracle就要分配更多的第一级位图块来管理Block,进而这些一级位图块又需要管理,于是又引出了二级位图块,Oracle最多支持三级位图块。

注意这个Block上还记录了另外一个信息“parent dba: 0x00c0000a”,这里也就是指二级位图块的地址,0a就是第10个Block,转储一下第10个Block的内容:

注意这个二级位图块(SECONDLEVEL BITMAP BLOCK)正是记录了一级位图块的地址,L1 Ranges代表的就是这个内容,也正是每个区间的第一个Block,在这个块内同样包含了一个上级位图块地址,在这里是是pdba: 0x00c0000b,也就是块11。

为了方便rdba向文件号和数据块号的转换,可以创建如下函数:

现在转换0x00c0000b就更直观了:

转储文件3块11信息,这个数据块正是数据段的段头信息,段头中记录了哪些位图块管理单元被包含在对象中:

注意段头的数据块类型是Oracle9i中新增的“type:0x23=PAGETABLE SEGMENT HEADER”,在段头的最后部分记录了二级位图块的地址:

Second Level Bitmap block DBAs ------------------------------------------------------- DBA 1: 0x00c0000a

所以通常SEGMENT HEADER也被看作是第一个Level 3级的位图块,如果SEGMENT HEADER的空间不足以存储二级位图块的指针,那么新的Level 3级位图块将被创建。

也可以DUMP一下第89个位图块:

SQL> alter system dump datafile 3 block 89; System altered.

其内容就包括了未使用(unformatted)的数据块,其二级位图块同样指向了0x00c0000a:

如果删除部分数据,就可以看到空间记录的变化:

再看块9的内容:

注意:在实际的情况中,每个一级位图块并非特定管理16个块的空间信息,当创建一个UniformSize为5MB的表空间,其位图块要管理64个Block。

SQL> create tablespace test datafile '/opt/oracle/test.dbf' size20M 2 EXTENT MANAGEMENT LOCAL UNIFORM SIZE5M 3 SEGMENT SPACE MANAGEMENT AUTO 4 / Tablespace created.

创建测试对象:

简要转储信息:

总结一下,ASSM的三级位图块的结构如图5-5所示:

通常Segment Header同时被认为是第一个三级位图块,这个位图块包含一系列指向二级位图块的指针,当这个数据块的空间不足以存储2级位图块的地址时,第一个真正独立的三级位图块将会产生。由于Segment Header已经可以胜任极大数据量的对象的空间管理,所以通常很难观察到其他三级位图块的出现。曾经有朋友创建了900G左右的数据表,仍然没有新的三级位图块出现。

为了验证以上结构猜想,进行以下测试实验,实验要能够实现:

(1)更快速的区间分配与扩展; (2)使segment header尽量小,以便进一步扩展。

为此可以创建一个2kB block_size的表空间,设置uniform size区间大小为10kB,这样可以尽量缩减空间耗用:

SQL> create tablespace eygle 2 datafile 'd:\EYGLE01.DBF' size1024Mreuse blocksize 2048 3 extent management local uniform size 10k 4 segment space management auto; 表空间已创建。 SQL> set timing on SQL> alter tablespace eygle add datafile 'f:\eygle02.dbf' size8191Mreuse; 表空间已更改。 已用时间: 00: 44: 42.08

创建一个数据表,设置高pctfree值,使得每个Block只存储一行数据,然后插入1千万记录:

SQL> create table EYGLE 2 (ID NUMBER(8), 3 UNAME CHAR(1000) ) 4 tablespace eygle 5 pctfree 50 6 initrans 1 7 maxtrans 255 8 ; 表已创建。 SQL> begin 2 for i in 1 .. 100 loop 3 for i in 1 .. 100000 loop 4 insert into eygle values(i,'eygle'); 5 end loop; 6 commit; 7 end loop; 8 end; 9 /

这个表占用了大约9GB空间,用完了表空间的所有空间:

SQL> select bytes/1024/1024/1024 sizegb from dba_segments 2 where segment_name='EYGLE'; SIZEGB ---------- 8.9988327

此时第一个3级位图块出现了。首先来看一下Segment Header,也就是PAGETABLE SEGMENT HEADER的信息,寻找Segment Header可以查询dba_segments视图:

转储数据文件12数据块35得到以下信息:

注意这里的First Level 3 BMB和Last Level III BMB已经出现,同时指向了另外一个数据块0x037d86de,这个地址转换出来就是datafile 13 block 4032222:

SQL> select getbfno('0x037d86de') bfno from dual; BFNO ------------------------------ datafile# is:13 datablock is:4032222

转储这个三级位图块的信息如下:

以上就是一个难得一见的三级位图块,这个位图块记录了一系列的L2级位图块地址,同时记录下一个三级位图块的指针(next)。为了取得这个三级位图块,在Segment Header上已经记录了237个二级指针:

进一步的插入数据,直至下一个三级位图块生成,此时SegmentHeader记录的信息如下:

这里记录的First Level 3 BMB仍然指向地址0x037d86de,而Last Level III BMB指向了新的三级位图块0x0472fcd7。再次转储此时的First Level 3 BMB 0x037d86de:

注意这里的Next指针已经指向了下一个三级位图块0x0472fcd7,

SQL> select getbfno('0x0472fcd7') bfno from dual; BFNO ------------------------------ datafile# is:17 datablock is:3341527

最后记录一下这个新的三级位图块:

根据以上的实验数据可以知道:ASSM的三级位图块之间以单向指针相连,Segment Header是一个例外,同时记录First和Last三级位图块的地址,使得三级位图块的链接形成了一个链接环,从而实现了三级位图块之间的导航。

尽管ASSM显示出了令人激动的特性并能够简化Oracle DBA的工作,但是Oracle 9iR2的位图分段管理还是有一些局限性的,这些局限主要包括:

  • 一旦ASSM表空间被创建,DBA将无法控制表空间内部的数据表和索引的存储行为;
  • ASSM不能用于创建临时的表空间,这是由排序时临时段的短暂特性决定的;
  • 只有本地管理的表空间才能够使用ASSM管理技术(鉴于LMT已经成功地取代了DMT,这实际上已经算不上限制);
  • 在高并发DML(例如INSERT、UPDATE和DELETE等)操作环境中,ASSM可能会出现性能上的问题。

正因为ASSM还不是太稳定与完善,所以至少在9iR2的版本上,还不建议生产系统中大规模使用ASSM的表空间。注意在Oracle 9i中,主要的缺省表空间都没有使用ASSM技术:

当创建表空间时,Oracle缺省地使用手工段管理方式:

而在Oracle 10g/11g中,Oracle已经将ASSM技术逐渐应用到缺省表空间中:

并且Oracle 10g/11g已经将ASSM作为默认的表空间管理模式:

这说明ASSM技术已经逐渐成熟,并且开始值得信赖。

要了解一项技术的另外一个侧面是参考Oracle的Bug列表,在Oracle 10g 10.2.0.3的补丁修正列表里,可以看到与ASSM有关的Bug修正,如表5-1所示

如下是Oracle 11g 11.2.0.2中修正的关于ASSM的bug列表(ASSM Space Management - Bitmap Managed Segments 部分):

11.2.0.2中修正的ASM Bug列表

当然,这些Bug大多数情况下都不会遇到,关注一下这些信息可以让我们从更多侧面了解Oracle技术。

延迟段空间创建(Deferred Segment Creation)

在OracleDatabase 11g之前,当创建一个实体对象时,如创建一个数据表,数据库即为该对象创建段(Segment),并随之分配一定数量的区间(Extent),这一状况在11g中发生了改变,延迟段空间创建(Deferred Segment Creation)技术被引入到数据库中,这个特性的功能是:当创建一个对象时(11.2.0.2之前不支持分区对象),数据结构定义被存储,但是并不立即创建数据段,直到有第一行记录插入时才动态创建分配段空间。

这个特性的一个优点是可以快速初始化数据库并降低空间开销,很多数据库系统初始化时会批量创建大量的数据表,如果不分配空间则可以大幅度提高初始化速度,而在有些系统中,可能很多数据表永远都不会存储数据,那么这个特性使得最基本的空间分配都不需要了。

初始化参数deferred_segment_creation用于控制该特性,设置为False可以关闭这个功能:

除了这个参数之外,在建表时也可以通过指定SEGMENT参数来定义是IMMEDIATE还是DEFERRED方式来创建数据段:

以下通过测试来简要说明一下这个新的特性。

SQL> create user eyglee identified by eyglee; SQL> grant connect,resource,dba to eyglee; SQL> connect eyglee/eyglee Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 Connected as eyglee SQL> create table dsc as select * from dba_tables where 1=0;

Table created

注意此时创建的对象未创建数据段:

SQL> select segment_name,bytes from user_segments; SEGMENT_NAME BYTES -------------------------------------------------------------------------------- ---------- Executed in 1.201 seconds

插入一条记录之后,空间分配:

SQL> insert into dsc select * from dba_tables where rownum <2; 1 row inserted SQL> select segment_name,bytes from user_segments; SEGMENT_NAME BYTES ------------------- ---------- DSC 65536

11.2.0.2中,TRUNCATE命令得到了增强, TRUNCATE TABLE中的"DROP ALL STORAGE"选项可以彻底删除SEGMENTS,来比较一下TRUNCATE语句的不同选项:

对于未分配空间的对象,新增加的特性还包括通过DBMS_SPACE_ADMIN.MATERIALIZ E_ DEFERRED_SEGMENTS实体化延迟段对象:

对于从11.2.0.2之前版本升级的系统,如果有空表,可以通过DBMS_SPACE_ADMIN.DROP_EMPTY_SEGMENTS过程清除这些SEGMENTS.

延迟段空间创建特性自11.2.0.2开始支持分区表,并且对于分区表,新分配的segments创建时缺省的extent size为8M,而不再是以前的64K:

在OracleDatabase 11gR1中,exp工具将无法导出这些使用延迟创建方式创建的数据表,这是因为exp工具存在BUG,使用expdp不存在这个问题,并且该问题在11gR2中被修正:

exp file=tab.dmp tables=dsc userid=eygle/eygle About to export specified tables via Conventional Path … EXP-00011: EYGLE.DSC does not exist Export terminated successfully with warnings.

这是段空间管理上,Oracle的又一个小小增强。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-01-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据和云 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档