详解Oracle本地管理表空间

如题所述

第1个回答  2022-11-18

   名词解释与约定表空间(Tablespace) 为数据库提供使用空间的逻辑结构 其对应物理结构是数据文件 一个表空间可以包含多个数据文件

  本地管理表空间(Locally Managed Tablespace简称LMT) i以后出现的一种新的表空间的管理模式 通过本地位图来管理表空间的空间使用

  字典管理表空间(Dictionary Managed Tablespace简称DMT) i以前包括以后都还可以使用的一种表空间管理模式 通过数据字典管理表空间的空间使用

  段(Segment) 数据库一种逻辑结构 如表段 索引段 回滚段等 段存在于表空间中 并对应一定的存储空间

  区间 可以简称区(Extent) 段的存储可以分成一个或多个区间 每个区间占用一定数量的数据块(block) 在本地管理的表空间中 表空间的Extent就对应段的Extent 块(Block) 数据库最小的存储单位 在本文中Block的大小约定为 字节

  位(Bit) 本地管理表空间的空间管理单位 一个位可能等于一个区间 也可能多个位组成一个区间

   本地管理表空间 语法在Oracle I的版本中 Oracle推出了一种全新的表空间管理方式 本地化管理的表空间 所谓本地化管理 就是指Oracle不再利用数据字典表来记录Oracle表空间里面的区的使用状况 而是在每个表空间的数据文件的头部加入了一个位图区 在其中记录每个区的使用状况 每当一个区被使用 或者被释放以供重新使用时 Oracle都会更新数据文件头部的这个记录 反映这个变化

  本地化管理的表空间的创建过程 语法 CREATE TABLESPACE 表空间名字 DATAFILE 数据文件详细信息 [EXTENT MANAGEMENT { LOCAL {AUTOALLOCATE | UNIFORM [SIZE INTETER [K|M] ] } } ]关键字EXTENT MANAGEMENT LOCAL 指定这是一个本地化管理的表空间 对于系统表空间 只能在创建数据库的时候指定EXTENT MANGEMENT LOCAL 因为它是数据库创建时建立的第一个表空间

  在 i中 字典管理还是默认的管理方式 当选择了LOCAL关键字 即表明这是一个本地管理的表空间 当然还可以继续选择更细的管理方式 是AUTOALLOCATE 还是 UNIFORM 若为AUTOALLOCATE 则表明让Oracle来决定区块的使用办法 若选择了UNIFORM 则还可以详细指定每个区块的大小 若不加指定 则为每个区使用 M大小

   本地管理优点 本地化管理的表空间避免了递归的空间管理操作 而这种情况在数据字典管理的表空间是经常出现的 当表空间里的区的使用状况发生改变时 数据字典的表的信息发生改变 从而同时也使用了在系统表空间里的回滚段

   本地化管理的表空间避免了在数据字典相应表里面写入空闲空间 已使用空间的信息 从而减少了数据字典表的竞争 提高了空间管理的并发性 区的本地化管理自动跟踪表空间里的空闲块 减少了手工合并自由空间的需要

   表空间里的区的大小可以选择由Oracle系统来决定 或者由数据库管理员指定一个统一的大小 避免了字典表空间一直头疼的碎片问题

   从由数据字典来管理空闲块改为由数据文件的头部记录来管理空闲块 这样避免产生回滚信息 不再使用系统表空间里的回滚段 因为由数据字典来管理的话 它会把相关信息记在数据字典的表里 从而产生回滚信息

  由于这种表空间的以上特性 所以它支持在一个表空间里边进行更多的并发操作 并减少了对数据字典的依赖

   本地管理表空间管理机制表空间是一种为段(表 索引等)提供空间的逻辑结构 所以 当在表空间中增加 删除段的时候 数据库就必须跟踪这些空间的使用

  如下例所示 假定一个新创建的表空间包含了五个表表一……表二……表三……表四……表五……未用空间当我们删除表四的时候 就有如下结果表一……表二……表三……空闲空间段……表五……未用空间很明显 ORACLE需要有一个机制来管理表空间中各数据文件的这些分配的或未分配的空间 为了跟踪这些可以使用的空间(包括未分配使用的和可以重复使用的) 对于每一个空间 我们必须知道 这个可用空间位于什么数据文件 这个空间的尺寸是多大 如果它在用了 是哪一个段占用的这个空间直到 i之前 所有的表空间都是采用字典管理模式 为了确保能保存以上的信息 ORACLE用了两个数据字典表 UET$(已使用的区间)或FET$(空闲空间) SQL> desc UET$ Name      Type   Nullable Default Comments

  

  SEGFILE#  NUMBER SEGBLOCK# NUMBER EXT#      NUMBER TS#       NUMBER FILE#     NUMBER BLOCK#    NUMBER LENGTH    NUMBER

  SQL> desc FET$ Name   Type   Nullable Default Comments

  

  TS#    NUMBER FILE#  NUMBER BLOCK# NUMBER LENGTH NUMBER查询该表可以看到 每个使用空间或空闲空间(不一定是一个extent 可以是多个extent)都在该表中对应了一行 它的工作方式是当一个段被删除的时候 ORACLE就移动UET$中相应的行到FET$ 这个过程的发生是连续的 而且可能发生等待 当并发性很高的时候 数据字典的争用就来了 另外有一个问题就是 当表的空间很不连续或表空间有大量的碎片引起这两个表的增大 那么也就会引起数据库性能上的下降

  本地管理表空间正是为了解决这一问题来的 在表空间的空间管理上 ORACLE将存储信息保存在表空间的头部的位图中 而不是保存在数据字典中 通过这样的方式 在分配回收空间的时候 表空间就可以独立的完成操作也不用与其它对象关系

  下面就让我们进入到本地管理表空间的内部 看看ORACLE是怎么实现这一工作的

   用Uniform方式的本地管理表空间 当uniform size值太小时SQL> create tablespace demo datafile /oradata/ltest/demo dbf size m extent management local uniform size k ORA Uniform size for auto segment space managed tablespace should have at least blocks注意 我实验环境block为 k 所以uniform size至少为 k 当storage参数中的initial为空时SQL> create tablespace demo datafile /oradata/ltest/demo dbf size m extent management local uniform size k Tablespace created SQL> select a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tablespaces a     where a tablespace_name = DEMO INIT_EXTENT(K) NEXT_EXTENT(K)

  

                   SQL> create table demotab (x number) tablespace demo Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOTAB TABLE_NAME                     INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOTAB                                                    注意 建表时没有存储参数initial时 初始化区与下一个区的大小都是 k 与uniform size的大小一样的

  SQL> select a bytes / INIT_EXTENT(K) from user_extents a where a segment_name = DEMOTAB and a extent_id = INIT_EXTENT(K)

  

   SQL> select count(*) from user_extents where segment_name = DEMOTAB COUNT(*)

  

   注意 在该段中 产生一个区

   当initial < uniform size时SQL> create table demotab _ (x number) tablespace demo storage (initial K next k) Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOTAB _ TABLE_NAME                     INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOTAB _                                                   注意 此时INIT_EXTENT为 不是initial参数的 SQL> select a bytes / INIT_EXTENT(K) from user_extents a where a segment_name = DEMOTAB _ and a extent_id = INIT_EXTENT(K)

  

   SQL> select count(*) from user_extents where segment_name = DEMOTAB _ COUNT(*)

  

   当initial > uniform size时SQL> create table demotab _ (x number) tablespace demo storage (initial K next k) Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOTAB _ TABLE_NAME                     INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOTAB _                                              注意 initial > uniform size时 初始化区的大小initial的大小

  SQL> select a bytes / INIT_EXTENT(K) from user_extents a where a segment_name = DEMOTAB _ and a extent_id = INIT_EXTENT(K)

  

   SQL> select count(*) from user_extents where segment_name = DEMOTAB _ COUNT(*)

  

   注意 此时分配的区已经不是 个了 是 个 在这种情况下initial就有起做作用 分配区的数量为 取整(initial/uniform size) +

  结论 在uniform size时 initial不管为多少时 这个段的每一个区大小都为uniform size的大小

   用autoallocate方式的本地管理表空间 当storage参数中的initial为空时SQL> create tablespace demoa datafile /oradata/ltest/demoa dbf size m extent management local autoallocate Tablespace created SQL> select a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tablespaces a     where a tablespace_name = DEMOA INIT_EXTENT(K) NEXT_EXTENT(K)

  

   SQL> create table demoatab(x number) tablespace demoa Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOATAB TABLE_NAME                    INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOATAB                                    SQL> select count(*) from user_extents where segment_name = DEMOATAB COUNT(*)

  

  

  SQL> select a segment_name a bytes a blocks from user_extents a where a segment_name = DEMOATAB_ SEGMENT_NA      BYTES     BLOCKS

  

  DEMOATAB_                 DEMOATAB_             rows selected当自动分配时 发现开始第一个区分配 个块( K) 到 区开始 每个区分配 个块(大小 M) 我做过实验当initial足够大时 第一个区的大小不一定都是 K 可以是 M M M 甚至是 M 当initial < uniform size时SQL> create table demoatab_ (x number) tablespace demoa storage (initial K next k) Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOATAB_ TABLE_NAME                     INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOATAB_                                   SQL> select a bytes / INIT_EXTENT(K) from user_extents a where a segment_name = DEMOATAB_ and a extent_id = INIT_EXTENT(K)

  

   SQL> select count(*) from user_extents where segment_name = DEMOATAB_ COUNT(*)

  

   当initial > uniform size时SQL> create table demoatab_ (x number) tablespace demoa storage (initial K next k) Table created SQL> select a table_name            a initial_extent / INIT_EXTENT(K)            a next_extent / NEXT_EXTENT(K)      from user_tables a     where a table_name = DEMOATAB_ TABLE_NAME                      INIT_EXTENT(K) NEXT_EXTENT(K)

  

  DEMOATAB_                                 SQL> select a bytes / INIT_EXTENT(K) from user_extents a where a segment_name = DEMOATAB_ and a extent_id = INIT_EXTENT(K)

  

   SQL> select count(*) from user_extents where segment_name = DEMOATAB_ COUNT(*)

  

   结论 ORACLE通过强制性的手段使本地管理表空间中的所有Extent是同样大小的 尽管可能自定义了不同的存储参数 在自动分配的本地管理的表空间中 区间尺寸可能由以下尺寸组成 K M M M 甚至是 M 但是不管多大 都有一个通用尺寸 k 所以 K就是该表空间的位大小

   检查uet$与fet$是否有数据SQL> select file# name from v$datafile FILE# NAME—— /oradata/LTEST/datafile/o _mf_system_ q w_ dbf /oradata/LTEST/datafile/o _mf_undotbs _ q ct_ dbf /oradata/LTEST/datafile/o _mf_sysaux_ q _ dbf /oradata/LTEST/datafile/o _mf_users_ q do_ dbf /oradata/LTEST/datafile/o _mf_example_ q jt _ dbf /oradata/LTEST/datafile/o _mf_bigtbs_ ct vw x_ dbf /oradata/ltest/demo dbf /oradata/ltest/demo dbf /oradata/ltest/demoa dbf rows selected可以检查uet$与fet$ SQL> select count(*) from uet$ where file# = COUNT(*)

  

   SQL> select count(*) from fet$ where file# = COUNT(*)

  

   采用本地管理的表空间 这两张视图中没有数据 下面就通过Dump块的信息 来进一步分析本地管理表空间的特点

   Dump数据文件中位图信息(第 个块到第 个块)

   dump第三个块数据文件的前两个块是文件头 所以dump第 个块 从第 个块到第 个块是该数据文件的数据文件的位图区 如果db_block_size为 那么占用的空间为 K 文也用另一种不是很严谨的方法验证了占用 K大小的问题

  SQL> alter system dump datafile block System altered Dump出来的信息如下 Start dump data blocks tsn file# minblk maxblk buffer tsn rdba x ( / )

  scn x ee d seq x flg x tail xee d e frmt x cval x e type x e=KTFB Bitmapped File Space Bitmap Hex dump of block st= typ_found= Dump of memory from x EFC to x F C EFC A E EE D   [……] EFC E C   [ C……] EFC F F   [……] EFC FF   [……] EFC   [……] Repeat times F BF EE D E   [……] File Space Bitmap Block BitMap Control                                   这句话说明该块还是位图区( 块都这样子 可dump每个块出来验证)

  RelFno BeginBlock Flag First Free F F     (共 行)

   ……

   End dump data blocks tsn file# minblk maxblk

  共 行 每行 个字节 每个字节 位 共有位数 * * = 前面两节的内容是 F F => => 个位为 与下面通过user_extents算出来的一样 还有空闲区共有 = (注意 位大小为 的个数与extent个数相等 只是一个巧合 因为位图管理中位大小为 对应的是 个block的使用情况 当一个区的分配大小不为 个block时 比如 个block时 两者就不会相等了 )

  可看表空间DEMO 中已经用了几个区

  SQL> select count(*) from user_extents a where a tablespace_name = DEMO COUNT(*)

  

   先扩展后 再dump第三个块SQL> alter table demotab allocate extent Table altered SQL> alter system dump datafile block System altered

  Dump出来的信息如下 Start dump data blocks tsn file# minblk maxblk buffer tsn rdba x ( / )

  scn x fc f seq x flg x tail xfc f e frmt x cval x type x e=KTFB Bitmapped File Space Bitmap Hex dump of block st= typ_found= Dump of memory from x EFC to x F C EFC A E FC F   [……O……] EFC C   [……] EFC F F   [……] EFC FF   [……] EFC   [……] Repeat times F BF FC F E   [……O ] File Space Bitmap Block BitMap Control RelFno BeginBlock Flag First Free F F ……

   End dump data blocks tsn file# minblk maxblk

  前面两节的内容是 F F => => 个位为 说明通过语句 alter table demotab allocate extent 又增加了一个区的分配

   Dump数据文件中数据信息(比如第 个块)

  查看dba_extents视图 也可以发现表DEMOTAB 从第 个块开始分配第一个区

  SQL> select a segment_name a file_id a block_id a extent_id from dba_extents a where a segment_name = DEMOTAB SEGMENT_NAME       FILE_ID   BLOCK_ID   EXTENT_ID

  

  DEMOTAB                                         DEMOTAB                                       

  Dump第 个块 这个块相当表头的信息

  SQL> alter system dump datafile block System altered Dump出来的信息如下 Start dump data blocks tsn file# minblk maxblk buffer tsn rdba x ( / )

  scn x fc f seq x flg x tail xfc f frmt x cval x aaf type x =FIRST LEVEL BITMAP BLOCK Hex dump of block st= typ_found= Dump of memory from x EFC to x F C EFC A FC F   [ ……O……] EFC AAF   [ Z……] EFC   [……] Repeat times EFC   [……] EFC FFFFFFFF D   [……] EFC   [……] EFC   [……] EFC C   […… ……] EFC A   [……] EFCA C   [……] EFCB   [……] EFCC CE D   [m……] EFCD   [……] EFCE   [……] EFCF   [……] Repeat times EFD   [……] EFD   [……] Repeat times F BF FC F   […… O ] Dump of First Level Bitmap Block

  

  nbits nranges          parent dba   x a   poffset unformatted       total         first useful block owning instance instance ownership changed at Last successful Search Freeness Status   nf       nf       nf       nf

  Extent Map Block Offset First free datablock Bitmap block lock opcode Locker xid        x c Inc # Objd HWM Flag HWM Set Highwater   x c  ext#       blk#       ext size #blocks in seg hdr s freelists #blocks below mapblk  x   offset

  

  DBA Ranges

  

   x   Length       Offset x   Length       Offset

   Metadata   Metadata   Metadata   unformatted unformatted   unformatted   unformatted   unformatted unformatted   unformatted   unformatted   unformatted unformatted   unformatted   unformatted   unformatted

  

lishixinzhi/Article/program/Oracle/201311/16723

相似回答