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

在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的又一个小小增强。

原文发布于微信公众号 - 数据和云(OraNews)

原文发表时间:2017-01-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏13blog.site

如约而至,Java 10 正式发布!

3 月 20 日,Oracle 宣布 Java 10 正式发布。 官方已提供下载:http://www.oracle.com/technetwork/java/...

3395
来自专栏个人分享

spark MapOutputTrackerMaster

最近用了一个RowNumber() over()函数 进行三张4000万数据的关联筛选,建表语句如下:

722
来自专栏企鹅号快讯

Java 9 逆天的十大新特性

在介绍 Java 9 之前,我们先来看看 Java 成立到现在的所有版本。 1990 年初,最初被命名为 Oak; 1995 年 5 月 23 日,Java 语...

1905
来自专栏非著名程序员

Retrofit--使用Retrofit时怎样去设置OKHttp

? 投稿作者:黄海杰 原文链接:http://blog.csdn.net/lyhhj/article/details/51388147 特别声明:本文为黄海...

1809
来自专栏人人都是极客

Linux用户态进程的内存管理

上一篇我们了解了内存在内核态是如何管理的,本篇文章我们一起来看下内存在用户态的使用情况,如果上一篇文章说是内核驱动工程师经常面对的内存管理问题,那本篇就是应用工...

712
来自专栏逸鹏说道

2.并发编程~先导篇(下)

代码实例:https://github.com/lotapp/BaseCode/tree/master/python/5.concurrent/Linux/进程...

703
来自专栏菩提树下的杨过

Linq to Sql中Single写法不当可能引起的数据库查询性能低下

场景:需要从T_User表中返回指字条件的某条记录的某一个字段 在Linq中有二种理论上都行得通的写法,见下面的代码: Code using (dbUserDa...

1956
来自专栏技术墨客

Vert.x工具—使用Dropwizard Metrics对指标进行监控(Metrics使用教程)

    最近项目中需要针对Vert.x的运行效率进行监控,查阅Vert.x官文,发现目前提供了Dropwizard和Hawkular两种开箱即用的工具。本文将介...

512
来自专栏逸鹏说道

1.并发编程~先导篇(上)

并发 :一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

733
来自专栏枕边书

用C写一个web服务器(一) 基础功能

前言 C 语言是一门很基础的语言,程序员们对它推崇备至,虽然它是我的入门语言,但大学的 C 语言知道早已经还给了老师,C 的使用可以说是从头学起。 之前一直在读...

1779

扫描关注云+社区