【循序渐进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 条评论
登录 后参与评论

相关文章

来自专栏数据和云

深入解析:由SQL解析失败看开发与DBA的性能之争

李华 云和恩墨高级技术顾问 以下案例来自大讲堂的一次分享,从这个案例中我们可以了解“错误的SQL”可能对数据库产生的种种影响。如何找到这些错误的、解析失败的S...

2905
来自专栏机器学习算法与Python学习

SQL Server常用命令(平时不用别忘了)

SQL Server 2008 在Microsoft的数据平台上发布,可以组织管理任何数据。可以将结构化、半结构化和非结构化文档的数据直接存储到数据库中。可以对...

2777
来自专栏杂烩

mycat安装使用 原

    github地址:https://github.com/MyCATApache/Mycat-Server/wiki

722
来自专栏从ORACLE起航,领略精彩的IT技术。

Oracle数据库该如何着手优化一个SQL

3034
来自专栏乐沙弥的世界

PGA的设置与调整

    PGA,即程序全局区(Program Global Area),是Oracle体系机构的重要组成部分。Oracle 数据库对系统内存的总开销即是PGA+...

552
来自专栏性能与架构

MySQL 清除表空间碎片

表的存储会出现碎片化,每当删除了一行内容,该段空间就会变为空白 当执行插入操作时,MySQL会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用...

3227
来自专栏Java帮帮-微信公众号-技术文章全总结

【数据库】MySQL进阶四、select

【数据库】MySQL进阶四、select mysql中select * for update 注: FOR UPDATE 仅适用于InnoDB,且必须在事务区...

4097
来自专栏Java3y

数据库面试题(开发者必看)

数据库常见面试题(开发者篇) ? ? 这里写图片描述 什么是存储过程?有哪些优缺点? 什么是存储过程?有哪些优缺点? 存储过程就像我们编程语言中的函数一样,封装...

3825
来自专栏Golang语言社区

二十种实战调优MySQL性能优化的经验

今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显。关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事...

442
来自专栏Linyb极客之路

Java性能微调之数据库性能

 大部分Java系统性能问题基本上是由于错误的数据库访问方式引起的,带来了大量额外日志和内存消耗,这些都会对JVM的垃圾回收造成冲击影响,本文主要针对这种错误的...

531

扫码关注云+社区