在了解dmt和lmt之前,先来简单的熟悉一下oracle数据库的逻辑结构,逻辑结构描速起来非常简单:表空间是由段(segment)组成的,段是由范围(extent)组成的,范围是由连续的(block)组成的。这里也可以通过一幅众所周知的图来表示:
当在表空间里创建一个table,index等对象时其实对我们使用者而言称其为对象,但是从oracle存储的角度来说把它称其为 segment。我们都知道oracle最小的读写单位是block,但是在为对象分配空间时单位却是extent,这样做的好处其实就是为了提高效率。 上面提到段是由范围组成的,当一个extent被分配给一个segment时,和segment对应的对象就可以使用空间,我们或许从来都不会关心 oracle内部到底是如何标记这个extnet是属于哪个segment的甚至也可能不会关心这个extent到底是属于哪一个datafile的,但 是对oracle而言,这却是一件非常重要的事情。oracle需要一种机制来跟踪或者记录一个数据文件中extent的使用、空闲情况。Dmt,lmt 就是针对表空间中extent是如何被管理而言的。
1、dmt (dictionary managed tablespace)
从oracle9.2开始,default的tablespace都是lmt的,而且也不支持创建dmt类型的表空间了:
SQL> create tablespace dmt datafile 'E:ORACLEPRODUCT10.2.0ORADATATESTDMT.D
BF' SIZE 3M extent management dictionary;
create tablespace dmt datafile 'E:ORACLEPRODUCT10.2.0ORADATATESTDMT.DBF' S
IZE 3M extent management dictionary
*
第 1 行出现错误:
ORA-12913: 无法创建字典管理的表空间
SQL>
除非在创建数据库时选择定制把system tablespace的区管理类型改成在字典中管理,否则在system tablespace类型是local的情况下是不支持创建dmt类型的表空间了。
另外值得一提的是从9.2开始,即使在创建db时指定temp tbs为字典管理的,通过dbca创建时可以指定,但是创建之后还是发现它是local管理的;使用命令创建时直接会报错:
SQL> col tablespace_name format a20
SQL> select tablespace_name , contents , extent_management from dba_tablespaces;
TABLESPACE_NAME CONTENTS EXTENT_MANAGEMENT
-------------------- ------------------ --------------------
SYSTEM PERMANENT DICTIONARY
UNDOTBS1 UNDO LOCAL
SYSAUX PERMANENT LOCAL
TEMP TEMPORARY LOCAL
USERS PERMANENT LOCAL
DMT PERMANENT DICTIONARY
已选择6行。
上面查询显示system tbs是dictionary
SQL> create temporary tablespace tmp tempfile 'E:ORACLEPRODUCT10.2.0ORADATA
DMTTMP.DBF' SIZE 5M extent management dictionary;
create temporary tablespace tmp tempfile 'E:ORACLEPRODUCT10.2.0ORADATADMTT
MP.DBF' SIZE 5M extent management dictionary
*
ERROR at line 1:
ORA-25139: invalid option for CREATE TEMPORARY TABLESPACE
undo tbs在通过dbca建库时也不允许指定为dictionary类型,命令方式同样如此:
SQL> create undo tablespace undotbs2 datafile 'E:ORACLEPRODUCT10.2.0ORADATA
UNDOTBS02.DBF' size 3m extent management dictionary;
create undo tablespace undotbs2 datafile 'E:ORACLEPRODUCT10.2.0ORADATAUNDOT
BS02.DBF' size 3m extent management dictionary
*
ERROR at line 1:
ORA-30024: Invalid specification for CREATE UNDO TABLESPACE
说了半天,到底什么是dmt,其实非常容易理解,当在tbs上创建segment时,表空间里相应的数据文件中
的extent是被使用了还是处于空闲是记录在两个数据字典表中(uet$:used extent;fet$:free extent),
也就是说Oracle updates the appropriate tables in the data dictionary whenever an extent is
allocated, or freed for reuse. 需要注意的是查询这两个表需要sys用户。
SQL> create table t(id int) tablespace dmt;
Table created.
SQL> select * from uet$ where segfile#<>1;
SEGFILE# SEGBLOCK# EXT# TS# FILE# BLOCK# LENGTH
---------- ---------- ---------- ---------- ---------- ---------- ----------
5 2 0 5 5 2 5
uet$字段简要介绍:
SEGFILE# segment header block所在的数据文件编号,对应dba_segments.header_file
SEGBLOCK# segment header block 编号,对应dba_segments.header_block
EXT# extent编号 对应dba_extents.extent_id TS# tbs编号 对应v$tablespace.ts# FILE# extent所在的datafile编号,对应dba_data_file.file_id BLOCK# extent的起始block编号,对dba_extents.block_id LENGTH 该extent从block#开始所包含的block的数量,对应dba_extents.blocks
SQL> select * from fet$ ;
TS# FILE# BLOCK# LENGTH
---------- ---------- ---------- ----------
0 1 13864 5337
5 5 7 186
fet$ 字段简要介绍:
TS# 同上
FILE# 同上
BLOCK# 数据文件file#上free block开始位置
LENGTH free block的长度,block的数量
在创建dmt tbs时指定的数据文件大小是3m:
SQL> select 3*1024*1024/16384 from dual;
3*1024*1024/16384 ----------------- 192
SQL>
192个block - 从uet$得知的从第二个block开始该extent总共包含5个block(也就是2~6),也就是fet$
中显示的从第7个block开始的186(192 - 7+1)个free block
这种管理extent的方式存在的严重问题就是并发性支持很弱,因为在用户使用对象的过程中只要涉及到extent的分配或者回收。oracle内 部都会对这两个表进行修改,对象越大,涉及到的extent数量越多,对这两个表修改锁定( ST (space transaction) lock )的时间就越长。如果并发用户再要多,这两个表上的资源争夺可想而知。另外在修改uet$和fet$的同时本身也是需要undo和redo的,而占用的 undo和redo和修改普通表没有什么两样,因此对undo和redo资源本身也是一个冲击。oracle也意识到了dmt存在的严重缺陷,于是从 9.2开始推出了lmt。
另外在创建dmt时可以设置控制extent变化的storage参数,这些参数对tbs而言本身没有太多意义,它的作用在于在tbs中为segmeng分配extent时extent的变化情况:
SQL> create tablespace dmt1 datafile 'E:ORACLEPRODUCT10.2.0ORADATADMTDMT01 .DBF' SIZE 10M default storage( 2 initial 64k 3 next 128k 4 pctincrease 50 5 minextents 1 6 maxextents unlimited 7 ) 8 extent management dictionary;
表空间已创建。
SQL> create table t_dmt1(id int) tablespace dmt1;
表已创建。
SQL> COL TABLE_NAME FORMAT A10 SQL> SELECT TABLE_NAME , INITIAL_EXTENT,NEXT_EXTENT,MIN_EXTENTS,MAX_EXTENTS,PCT_ INCREASE FROM DBA_TABLES WHERE TABLE_NAME='T_DMT1';
TABLE_NAME INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS PCT_INCREASE ---------- -------------- ----------- ----------- ----------- ------------ T_DMT1 65536 131072 1 2147483645 50
SQL>
我们清楚的看到创建在dmt1表空间上的表t_dmt1完全使用了dmt1上的default storage参数,当然也可以在建表时在table上指定storage参数,这里不在赘述,有机会介绍table时在做介绍。
2、lmt (locally managed tablespace)
lmt在记录extent是否是free还是used是通过在数据文件开头的几个block中通过bit位来记录的。
数据库中如果不存在dmt类型的表空间,则uet$和fet$中不在有信息。
SQL> select count(*) from uet$;
COUNT(*) ---------- 0
SQL> select count(*) from fet$;
COUNT(*) ---------- 0
SQL>
下面创建一个tbs来测试一下:
SQL> create tablespace lmt datafile 'E:ORACLEPRODUCT10.2.0ORADATATESTlmt.d bf' size 5m;
表空间已创建。
SQL> drop table t; drop table t * 第 1 行出现错误: ORA-00942: 表或视图不存在
SQL> create table t(id int) tablespace lmt ;
表已创建。 SQL> COL segment_name format a3 SQL> select segment_name , extent_id , file_id , block_id , blocks from dba_exte nts where segment_name='T' AND owner='SYS';
SEG EXTENT_ID FILE_ID BLOCK_ID BLOCKS --- ---------- ---------- ---------- ---------- T 0 5 9 8
SQL>
BLOCK_ID=9我们知道oracle是从第9个block开始给用户使用的,那么1~8这8个block都是做什么的?众所周知第一个block是datafile header,接下来我们dump 2~8:
摘录dump部分内容如下:
Start dump data blocks tsn: 14 file#: 5 minblk 2 maxblk 8 buffer tsn: 14 rdba: 0x01400002 (5/2) scn: 0x0000.0014eff2 seq: 0x02 flg: 0x04 tail: 0xeff21d02 frmt: 0x02 chkval: 0xba0e type: 0x1d=KTFB Bitmapped File Space Header Hex dump of block: st=0, typ_found=1 Dump of memory from 0x04DC2200 to 0x04DC4200 4DC2200 0000A21D 01400002 0014EFF2 04020000 [......@.........] 4DC2210 0000BA0E 00000005 00000008 00000280 [................] 4DC2220 00000001 00000000 00000000 00000007 [................] 4DC2230 00000280 00000001 0000004E 00000000 [........N.......] 4DC2240 00000000 00000000 00000000 00000000 [................] 4DC2250 00000009 00000008 00000000 00000000 [................] 4DC2260 00000000 00000000 00000000 00000000 [................] Repeat 504 times 4DC41F0 00000000 00000000 00000000 EFF21D02 [................] File Space Header Block: Header Control: RelFno: 5, Unit: 8, Size: 640, Flag: 1 AutoExtend: NO, Increment: 0, MaxSize: 0 Initial Area: 7, Tail: 640, First: 1, Free: 78 Deallocation scn: 0.0 Header Opcode: Save: No Pending Op
buffer tsn: 14 rdba: 0x01400003 (5/3) scn: 0x0000.0014eff2 seq: 0x01 flg: 0x04 tail: 0xeff21e01 frmt: 0x02 chkval: 0x4eba type: 0x1e=KTFB Bitmapped File Space Bitmap Hex dump of block: st=0, typ_found=1 Dump of memory from 0x04DC2200 to 0x04DC4200 4DC2200 0000A21E 01400003 0014EFF2 04010000 [......@.........] 4DC2210 00004EBA 00000005 00000009 00000000 [.N..............] 4DC2220 00000001 0000F7FF 00000000 00000000 [................] 4DC2230 00000000 00000000 00000001 00000000 [................] 4DC2240 00000000 00000000 00000000 00000000 [................] Repeat 506 times 4DC41F0 00000000 00000000 00000000 EFF21E01 [................] File Space Bitmap Block: BitMap Control: RelFno: 5, BeginBlock: 9, Flag: 0, First: 1, Free: 63487 0100000000000000 0000000000000000
..................................
其中第二个block "type: 0x1d=KTFB Bitmapped File Space Header以及内容File Space Header Block: Header Control: RelFno: 5, Unit: 8, Size: 640, Flag: 1 AutoExtend: NO, Increment: 0, MaxSize: 0 Initial Area: 7, Tail: 640, First: 1, Free: 78 ...."记录的显然是数据文件的信息,不过感觉这部
分内容为什么不记录在第一个block中?
从3~8其类型都是:type: 0x1e=KTFB Bitmapped File Space Bitmap,显然这6个block是真真代替uet$
和fet$来记录extent的使用、空闲状态的,接下来看看是如何记录的:
第3个block的信息"01000000.................... "是16进制数,转为二进制有意义的信息是:0000 0001,
其中只有1个"1"表示的正是1个64k的extent;下面创建一个拥有多个extents的segment看看效果:
SQL> create table tt(id int) storage(initial 2m) tablespace lmt;
表已创建。
SQL> select count(*) from dba_extents where owner='SYS' AND segment_name='TT';
COUNT(*) ---------- 2
SQL> alter system dump datafile 5 block 3;
系统已更改。
主要信息摘录如下:
0100FFFFFFFF0000
转为为二进制:
0000 0001 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111
其中0000 0001代表的就是表t所使用的extent,而后面的32个1代表的就是32个64k的extent,正好是2m,当然在dba_extents中显示 的是2个extent,而oracle在标记的时候始终是以64k为单位标记的。至此lmt是如何记录extent的free 、used想必已经很清楚了。
SQL> select 32*64 from dual;
32*64 ---------- 2048
SQL>
另外在创建lmt类型的tbs时不再支持default storage这些参数,取而代之是autoallocate以及uniform,
default的是autoallocate,autoallocate分配extent的原则是:
segment<=1m ,以64k为单位分配extent; segment<=64m ,以1m为单位分配extent; segment<=1g ,以8m为单位分配extent; segment>1g ,以64m为单位分配extent. 比dmt时的pctincrease强不到哪儿去,尤其时当segment>1g之后,分配extent对连续空间的请求是很大的,因此建议当segmeng很大时最好使用unifom。以免造成系统还有很多空闲空间时结果系统还是报不能扩展...错误。 system tbs必须是autoallocate。
3、dmt和lmt的相互转化
4、mssm (manual segment space management)
dmt,lmt是管理segment中的extent的,而mssm和assm是管理extent中的block的。mssm是通过 segment header上的freelist 列表在管理extent上处于hwm(high warter mark)下的那些没有达到pctfree和曾经达到过pctfree但是后来由于delete等操作空间又紧缩下降到pctused的那些来自不同 extent的block所组成的(doc:A free list is a list of free data blocks that usually includes blocks existing
in a number of different extents within the segment. Free lists are composed of blocks in which free space has not yet reached PCTFREE or used space has shrunk below PCTUSED. Specify the number of process free lists with the FREELISTS parameter. The default value of
FREELISTS is one. The maximum value depends on the data block size.)。使用mssm来管理block时需要在创建表空间时指定manual segment space management语句:
SQL> create tablespace mssm datafile 'E:ORACLEPRODUCT10.2.0ORADATATESTmssm .dbf' size 3m segment space management manual;
表空间已创建。
SQL> 需要说明的时不论在dmt还时lmt下都可以使用mssm,而且在dmt下只能使用mssm,而下面要介绍的assm只在lmt下才支持。
了解了mssm的机制之后,使用上具体表现在创建segment时需要说明pctused , freelists, freelist
groups参数,当然如果不设置这些参数系统会使用default值。简单的做个测试:
SQL> create table t( id int ,name char(1000)) 2 storage( 3 freelists 1 4 freelist groups 1 5 ) 6 pctfree 50 7 pctused 50 8 tablespace mssm;
表已创建。
SQL>
这里指定了freelists=1 freelist groups=1 其实他们的default值也都是1,只是给出大家语法而已,另外pctfree 和pctused的default值是10,40。这个值是个百分数,pctfree 表示block的free空间要保留blcok大小的pctfree,其目的当然就是避免事后由于update操作造成行迁移。行迁移的内容这里暂时不会 多讲。正常情况下,如果hwm下一个block的使用空间没有达到block_size*(1-pctfree),那么这个block始终是在 freelists列表上的,如果使用空间达到了block_size*(1-pctfree),那么这个block脱离了freelists列表;如果 这个block上的数据后来由于各种操作在缩小以至于小于block_size*pctused了,那么这个block又重新回到了freelists列 表上,意味着在freelists列表上的block都有空闲空间供我们使用,如果segment上要存储数据,oracle优先使用freelists 列表上的block,当然append方式插入数据除外。有关pctfree 和pctused这里有段话说得很精辟(PCTFREE specifies the percentage of a data
block to be reserved (kept free) for possible updates to rows that already are contained in
that block. After a block becomes full, as determined by PCTFREE, Oracle does not consider
the block is for the insertion of new rows until the percentage of the block being used
falls below the parameter PCTUSED.) 简单的做个测试:
SQL> insert into t values(1 , 'a');
已创建 1 行。
SQL> insert into t values(2 , 'b');
已创建 1 行。
SQL> insert into t values(3 , 'c');
已创建 1 行。
SQL> insert into t values(4 , 'd');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select id , substr(name , 1 , 1) , rowid from t;
ID SU ROWID ---------- -- ------------------ 1 a AAACdCAAGAAAAAKAAA 2 b AAACdCAAGAAAAAKAAB 3 c AAACdCAAGAAAAAKAAC 4 d AAACdCAAGAAAAALAAA
SQL> show parameter db_block_size
NAME TYPE VALUE ------------------------------------ ----------- -------------------- db_block_size integer 8192 SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 4 2 5 1
SQL> delete from t where id=1;
已删除 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 3 2 5 2
SQL>
通过上面试验(看rowid的变化,当然需要了解rowid,这里篇幅所限,rowid不做介绍,可能以后会专门介绍rowid)我们清晰的看到一 个block上只能存放3条数据,插入第4条时使用了另外一个blcok,对表分析之后发现NUM_FREELIST_BLOCKS(该字段表示 freelists上block的数量)=1,说明freelists上只有1个block,而这个block正是数据id=4所在的block,前3条 数据所在block由于使用空间达到了8k*(1-pctfree)=8k*0.5=4k因此从freelist上脱离了,之后删除了id=1这条数据之 后,这个block上存在2条数据,其占用的空间大约就是2k多一点,小于8k*pctused=8k*0.5=4k,因此这个blcok又回到了 freelists上,分析表之后显示的NUM_FREELIST_BLOCKS=2也正好说明了这一点。
继续插入数据:
SQL> select id , substr(name , 1 , 1) , rowid from t;
ID SU ROWID ---------- -- ------------------ 2 b AAACdCAAGAAAAAKAAB 3 c AAACdCAAGAAAAAKAAC 4 d AAACdCAAGAAAAALAAA
SQL> insert into t values(5 , 'e');
已创建 1 行。
SQL> select id , substr(name , 1 , 1) , rowid from t;
ID SU ROWID ---------- -- ------------------ 2 b AAACdCAAGAAAAAKAAB 3 c AAACdCAAGAAAAAKAAC 4 d AAACdCAAGAAAAALAAA 5 e AAACdCAAGAAAAALAAB
SQL> insert into t values(6 , 'f');
已创建 1 行。
SQL> select id , substr(name , 1 , 1) , rowid from t;
ID SU ROWID ---------- -- ------------------ 2 b AAACdCAAGAAAAAKAAB 3 c AAACdCAAGAAAAAKAAC 4 d AAACdCAAGAAAAALAAA 5 e AAACdCAAGAAAAALAAB 6 f AAACdCAAGAAAAALAAC
SQL> insert into t values(7 , 'g');
已创建 1 行。
SQL> select id , substr(name , 1 , 1) , rowid from t;
ID SU ROWID ---------- -- ------------------ 7 g AAACdCAAGAAAAAKAAA 2 b AAACdCAAGAAAAAKAAB 3 c AAACdCAAGAAAAAKAAC 4 d AAACdCAAGAAAAALAAA 5 e AAACdCAAGAAAAALAAB 6 f AAACdCAAGAAAAALAAC
已选择6行。
SQL> commit;
提交完成。
我们通过观察rowid的变化发现oracle优先使用了freelists上的block,并没有分配新的block。当然也可以通过analyze之后看hwm之下block的数量也是2来断定。不过这次发现NUM_FREELIST_BLOCKS这个时候是1
而不是我们期望的0。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 6 2 5 1
继续插入数据观察一下发现倒是没有问题:
SQL> insert into t values(8 , 'h');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 7 3 4 1
SQL>
为什么上面hwm下没有了free block,而NUM_FREELIST_BLOCKS=1不是0,请看下面的测试: SQL> select id , substr(name , 1 , 1) , rowid,ROWNUM , dbms_rowid.rowid_block_nu mber(rowid) block_number from t;
ID SU ROWID ROWNUM BLOCK_NUMBER ---------- -- ------------------ ---------- ------------ 7 g AAACdCAAGAAAAAKAAA 1 10 4 d AAACdCAAGAAAAAKAAD 2 10 5 e AAACdCAAGAAAAAKAAE 3 10 4 d AAACdCAAGAAAAALAAA 4 11 5 e AAACdCAAGAAAAALAAB 5 11 6 f AAACdCAAGAAAAALAAC 6 11 8 h AAACdCAAGAAAAAMAAA 7 12 9 i AAACdCAAGAAAAAMAAB 8 12 7 g AAACdCAAGAAAAAMAAC 9 12 6 f AAACdCAAGAAAAANAAA 10 13 8 h AAACdCAAGAAAAANAAB 11 13
ID SU ROWID ROWNUM BLOCK_NUMBER ---------- -- ------------------ ---------- ------------ 9 i AAACdCAAGAAAAANAAC 12 13
已选择12行。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 12 4 3 1
SQL> ALTER system dump datafile 6 block 9;
系统已更改。
查看dump文件freelists中相关内容发现:“SEG LST:: flg: USED lhd: 0x0180000d ltl: 0x0180000d
” freelists上的这个block是13,也就是说block13是最后一个满了的,最后一个虽然满了,但是在没有新的blck加入到freelists上之前这个block是不会从freelists上消失的。 继续插入数据: SQL> insert into t values(10,'j');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 13 5 2 1
SQL> ALTER system dump datafile 6 block 9;
系统已更改。 查看dump内容:“SEG LST:: flg: USED lhd: 0x0180000e ltl: 0x0180000e” 发现这次freelists上的block是为新插入数据分配的14号block,13号block从freelists脱离了,那么什
么时候 NUM_FREELIST_BLOCKS=0,当hwm下没有block时: SQL> truncate table t;
表被截断。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks, num_freelist_blocks 2 from dba_tables where table_name='T' and owner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS ---------- ---------- ------------ ------------------- 0 0 7 0
SQL>
mssm就是这样一种机制来管理block的空闲和使用情况的,这种方式管理block存在的缺陷主要就是当并发用户针对同一个segment请求 空间比较多时,会在segment header上的freelists上争夺激烈,具体tom给出的引水机的例子非常贴切,大家可以查看tom的力作。
有关freelists , freelist groups的深入了解也可以看以下几位大师的精彩讨论: [url]http://tech.it168.com/o/2006-04-11/200604112314992.shtml[/url]
5、assm (automatic segment space management)
在介绍mssm时提到mssm主要是对并发性的支持不是很好,如果并发用户同时在同一个segment上请求空间时在segment header会发生对freelists列表的争夺,基于此在lmt下oracle建议我们使用assm,看看oracle doc是如何来解释assm的:
This keyword tells Oracle that you want to use bitmaps to manage the free space within segments. A bitmap, in this case, is a map that describes the status of each data block within a segment with respect to the amount of space in the block available for inserting rows. As more or less space becomes available in a data block, its new state is reflected in the bitmap. Bitmaps enable Oracle to manage free space more automatically; thus, this form of space management is called automatic segment-space management.
Locally managed tablespaces using automatic segment-space management can be created as smallfile (traditional) or bigfile tablespaces. AUTO is the default.
以上doc是来之10.2,最后提到AUTO is the default.这是指10g的情况,在9i下manual是default的,下面看一下如何创建assm模式下的表空间:
SQL> create tablespace assm datafile 'E:oracleproduct10.2.0oradatatestassm .dbf' size 5m extent management local segment space manageme nt auto;
表空间已创建。 SQL> select tablespace_name , extent_management , segment_space_management from dba_tablespaces ;
TABLESPACE_NAME EXTENT_MAN SEGMEN ------------------------------ ---------- ------ SYSTEM LOCAL MANUAL UNDOTBS1 LOCAL MANUAL SYSAUX LOCAL AUTO TEMP LOCAL MANUAL ASSM LOCAL AUTO
SQL>
在创建表空间assm的语法中其实可以省略"extent management local segment space manageme nt auto",因为在10g下default的就是lmt下assm类型的。
下面来看看assm内部到底是如何通过block来实现利用bitmap管理segment上block的空闲和使用情况的。
测试如下:
SQL> create table tt tablespace assm as select * from dba_objects;
表已创建。
SQL> select EXTENT_ID , FILE_ID , BLOCK_ID , BLOCKS from dba_extents where segme nt_name='TT';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS ---------- ---------- ---------- ---------- 0 7 9 8 1 7 17 8 2 7 25 8 3 7 33 8 4 7 41 8 5 7 49 8 6 7 57 8 7 7 65 8 8 7 73 8 9 7 81 8 10 7 89 8 11 7 97 8 12 7 105 8 13 7 113 8 14 7 121 8 15 7 129 8 16 7 137 128
已选择17行。
SQL> select header_file,header_block,blocks,extents from dba_segments where segm ent_name='TT';
HEADER_FILE HEADER_BLOCK BLOCKS EXTENTS ----------- ------------ ---------- ---------- 7 11 256 17
SQL>
HEADER_BLOCK 显示的是11(segment header),而extent_id=0也就是说第一个extent是从第9个block开始的,那么9,10block到底做什么用了,dump下看看:
SQL> alter system dump datafile 7 block min 9 block max 11;
系统已更改。
dump主要内容摘录如下:
--===================================
Start dump data blocks tsn: 15 file#: 7 minblk 9 maxblk 11 buffer tsn: 15 rdba: 0x01c00009 (7/9) scn: 0x0000.001607e3 seq: 0x03 flg: 0x04 tail: 0x07e32003 frmt: 0x02 chkval: 0xa169 type: 0x20=FIRST LEVEL BITMAP BLOCK Hex dump of block: st=0, typ_found=1 Dump of memory from 0x07082200 to 0x07084200 ........... Dump of First Level Bitmap Block -------------------------------- nbits : 4 nranges: 2 parent dba: 0x01c0000a poffset: 0 unformatted: 0 total: 16 first useful block: 3 owning instance : 1 instance ownership changed at Last successful Search Freeness Status: nf1 0 nf2 0 nf3 0 nf4 0
Extent Map Block Offset: 4294967295 First free datablock : 16 Bitmap block lock opcode 0 Locker xid: : 0x0000.000.00000000 Inc #: 0 Objd: 10056 -------------------------------------------------------- DBA Ranges : -------------------------------------------------------- 0x01c00009 Length: 8 Offset: 0 0x01c00011 Length: 8 Offset: 8
0:Metadata 1:Metadata 2:Metadata 3:FULL 4:FULL 5:FULL 6:FULL 7:FULL 8:FULL 9:FULL 10:FULL 11:FULL 12:FULL 13:FULL 14:FULL 15:FULL -------------------------------------------------------- buffer tsn: 15 rdba: 0x01c0000a (7/10) scn: 0x0000.001607e3 seq: 0x09 flg: 0x04 tail: 0x07e32109 frmt: 0x02 chkval: 0xa07c type: 0x21=SECOND LEVEL BITMAP BLOCK Hex dump of block: st=0, typ_found=1 Dump of memory from 0x07082200 to 0x07084200 ................. Dump of Second Level Bitmap Block number: 10 nfree: 2 ffree: 8 pdba: 0x01c0000b Inc #: 0 Objd: 10056 opcode:0 xid: L1 Ranges : -------------------------------------------------------- 0x01c00009 Free: 1 Inst: 1 0x01c00019 Free: 1 Inst: 1 0x01c00029 Free: 1 Inst: 1 0x01c00039 Free: 1 Inst: 1 0x01c00049 Free: 1 Inst: 1 0x01c00059 Free: 1 Inst: 1 0x01c00069 Free: 1 Inst: 1 0x01c00079 Free: 1 Inst: 1 0x01c00089 Free: 5 Inst: 1 0x01c0008a Free: 5 Inst: 1
-------------------------------------------------------- buffer tsn: 15 rdba: 0x01c0000b (7/11) scn: 0x0000.001607e5 seq: 0x01 flg: 0x04 tail: 0x07e52301 frmt: 0x02 chkval: 0x8d53 type: 0x23=PAGETABLE SEGMENT HEADER Hex dump of block: st=0, typ_found=1 Dump of memory from 0x07082200 to 0x07084200 ............. Extent Control Header ----------------------------------------------------------------- Extent Header:: spare1: 0 spare2: 0 #extents: 17 #blocks: 256 last map 0x00000000 #maps: 0 offset: 2716 Highwater:: 0x01c0008c ext#: 16 blk#: 3 ext size: 128 #blocks in seg. hdr's freelists: 0 #blocks below: 131 mapblk 0x00000000 offset: 16 Unlocked -------------------------------------------------------- Low HighWater Mark : Highwater:: 0x01c0008c ext#: 16 blk#: 3 ext size: 128 #blocks in seg. hdr's freelists: 0 #blocks below: 131 mapblk 0x00000000 offset: 16 Level 1 BMB for High HWM block: 0x01c00089 Level 1 BMB for Low HWM block: 0x01c00089 -------------------------------------------------------- Segment Type: 1 nl2: 1 blksz: 8192 fbsz: 0 L2 Array start offset: 0x00001434 First Level 3 BMB: 0x00000000 L2 Hint for inserts: 0x01c0000a Last Level 1 BMB: 0x01c0008a Last Level II BMB: 0x01c0000a Last Level III BMB: 0x00000000 Map Header:: next 0x00000000 #extents: 17 obj#: 10056 flag: 0x10000000 Inc # 0 Extent Map ----------------------------------------------------------------- 0x01c00009 length: 8 0x01c00011 length: 8 0x01c00019 length: 8 0x01c00021 length: 8 0x01c00029 length: 8 0x01c00031 length: 8 0x01c00039 length: 8 0x01c00041 length: 8 0x01c00049 length: 8 0x01c00051 length: 8 0x01c00059 length: 8 0x01c00061 length: 8 0x01c00069 length: 8 0x01c00071 length: 8 0x01c00079 length: 8 0x01c00081 length: 8 0x01c00089 length: 128
Auxillary Map -------------------------------------------------------- Extent 0 : L1 dba: 0x01c00009 Data dba: 0x01c0000c Extent 1 : L1 dba: 0x01c00009 Data dba: 0x01c00011 Extent 2 : L1 dba: 0x01c00019 Data dba: 0x01c0001a Extent 3 : L1 dba: 0x01c00019 Data dba: 0x01c00021 Extent 4 : L1 dba: 0x01c00029 Data dba: 0x01c0002a Extent 5 : L1 dba: 0x01c00029 Data dba: 0x01c00031 Extent 6 : L1 dba: 0x01c00039 Data dba: 0x01c0003a Extent 7 : L1 dba: 0x01c00039 Data dba: 0x01c00041 Extent 8 : L1 dba: 0x01c00049 Data dba: 0x01c0004a Extent 9 : L1 dba: 0x01c00049 Data dba: 0x01c00051 Extent 10 : L1 dba: 0x01c00059 Data dba: 0x01c0005a Extent 11 : L1 dba: 0x01c00059 Data dba: 0x01c00061 Extent 12 : L1 dba: 0x01c00069 Data dba: 0x01c0006a Extent 13 : L1 dba: 0x01c00069 Data dba: 0x01c00071 Extent 14 : L1 dba: 0x01c00079 Data dba: 0x01c0007a Extent 15 : L1 dba: 0x01c00079 Data dba: 0x01c00081 Extent 16 : L1 dba: 0x01c00089 Data dba: 0x01c0008b --------------------------------------------------------
Second Level Bitmap block DBAs -------------------------------------------------------- DBA 1: 0x01c0000a
End dump data blocks tsn: 15 file#: 7 minblk 9 maxblk 11
--===================================
其中在第9个block的dump信息中我们发现type: 0x20=FIRST LEVEL BITMAP BLOCK,说明这个block是第一级bitmap block,oracle用第一级bitmap block来管理data block的使用情况:
-------------------------------------------------------- DBA Ranges : -------------------------------------------------------- 0x01c00009 Length: 8 Offset: 0 0x01c00011 Length: 8 Offset: 8
0:Metadata 1:Metadata 2:Metadata 3:FULL 4:FULL 5:FULL 6:FULL 7:FULL 8:FULL 9:FULL 10:FULL 11:FULL 12:FULL 13:FULL 14:FULL 15:FULL -------------------------------------------------------- 从上面内容(来自block 9的dump)发现9#block总共管理了16个block,也就是2个extent。由于extent是由连续的block组成的,因此只需要记录每个extent的起始block地址(0x01c00009)和extent的数量即可。
两个16进制的dba转化为10进制的分别是:
SQL> select dbms_utility.data_block_address_block(to_number('01c00009','xxxxxxxx ')) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(TO_NUMBER('01C00009','XXXXXXXX')) ----------------------------------------------------------------------- 9 SQL> select dbms_utility.data_block_address_block(to_number('01c000011','xxxxxxx xx')) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(TO_NUMBER('01C000011','XXXXXXXXX')) ------------------------------------------------------------------------- 17
SQL>
而block 9,17不正是我们上面查询dba_extents是显示的extent_id = 0 , 1两个extent
另外9# block dump信息中的:
0:Metadata 1:Metadata 2:Metadata
表示9#~11#block显示的是Metadata(元数据:数据仓库中非常重要的概念,管理数据的数据,oracle中的数据字典据都可以理解 成元数据),其中0表示是9#block,1 表示10#block,2 表示11#block(segment header),其他显示的都是full,表示这些block上都已经没有可用的空闲空间。同时也发现我们真真使用数据是从12#block开始的。
9#block dump内容里还有一个重要的信息就是parent dba: 0x01c0000a表示9#block的parent block 的地址,而这个block的地址正好是10#block的地址:rdba: 0x01c0000a。
至此9#block暂时分析完毕。
--==================================
再来10#block:
10#block的类型是:type: 0x21=SECOND LEVEL BITMAP BLOCK说明该block是二级bitmap block,他是用来管理一级bitmap block的。
10#block的主要dump信息:
L1 Ranges : -------------------------------------------------------- 0x01c00009 Free: 1 Inst: 1 0x01c00019 Free: 1 Inst: 1 0x01c00029 Free: 1 Inst: 1 0x01c00039 Free: 1 Inst: 1 0x01c00049 Free: 1 Inst: 1 0x01c00059 Free: 1 Inst: 1 0x01c00069 Free: 1 Inst: 1 0x01c00079 Free: 1 Inst: 1 0x01c00089 Free: 5 Inst: 1 0x01c0008a Free: 5 Inst: 1
--------------------------------------------------------
其中L1 Ranges 中的哪些dba转为10进制如下: 9 25 41 57 73 89 105 121 137 138
而这些值都是一级bitmap block的block_id,而这些值不正是dba_extents中显示的,同时也看到每一个一级bitmap block管理了16个data block。不过奇怪的是为什么138#block怎么也成了一级bitmap block了?暂时解释不清。
SQL> select block_id from dba_extents where segment_name='TT' AND mod(extent_id, 2)=0;
BLOCK_ID ---------- 9 25 41 57 73 89 105 121 137
已选择9行。
SQL>
再来看看10#block的 pdba: 0x01c0000b,这个地址正是11#block的dba:rdba: 0x01c0000b 。
接下来简单看看11#block的类型是:
type: 0x23=PAGETABLE SEGMENT HEADER
也就是我们熟悉的segment header block,这里它也同时是一个特殊的三级bitmap block同时最下面一条非常有用的信息是:
Second Level Bitmap block DBAs -------------------------------------------------------- DBA 1: 0x01c0000a
记录了二级btimap block的地址,因为segment小,只有1个二级bitmap block,大家也可以创建一个大一点的表,主要需要保证要有足够多的block才可能看到第二个二级block出现,要看到出现一个三级bitmap block可能非常的难。
感兴趣的话大家也可以参考eygle,piner两位版主的力作:
http://www.eygle.com/archives/2007/07/oracle_assm_level3_bmb.html http://www.itpub.net/thread-734505-1-3.html