我们这里讨论一下Oracle数据库中到底有多少类型的段,除了常见的TABLE、INDEX之外还有哪些?下面通过Oracle9i的数据字典来探讨Oracle的段类型。
SQL> select distinct segment_type from dba_segments; SEGMENT_TYPE ------------------ CACHE CLUSTER INDEX INDEX PARTITION LOBINDEX LOBSEGMENT NESTED TABLE ROLLBACK TABLE TABLE PARTITION TYPE2 UNDO 然而在DBA_SEGMENTS视图中,不一定包含了所有的段类型,我们从DBA_SEGMENTS的定义中去寻找Oracle的段类型。 SQL> select text from dba_views where view_name=’DBA_SEGMENTS’; TEXT ---------------------------------------------------------------------------------------------------- select owner, segment_name, partition_name, segment_type, tablespace_name, header_file, header_block, dbms_space_admin.segment_number_blocks(tablespace_id, relative_fno, header_block, segment_type_id, buffer_pool_id, segment_flags, segment_objd, blocks)*blocksize, dbms_space_admin.segment_number_blocks(tablespace_id, relative_fno, header_block, segment_type_id, buffer_pool_id, segment_flags, segment_objd, blocks), dbms_space_admin.segment_number_extents(tablespace_id, relative_fno, header_block, segment_type_id, buffer_pool_id, segment_flags, segment_objd, extents), initial_extent, next_extent, min_extents, max_extents, pct_increase, freelists, freelist_groups, relative_fno, decode(buffer_pool_id, 0, ‘DEFAULT’, 1, ‘KEEP’, 2, ‘RECYCLE’, NULL) from sys_dba_segs SQL> select text from dba_views where view_name=’SYS_DBA_SEGS’; TEXT -------------------------------------------------------------------------- select u.name, o.name, o.subname, so.object_type, s.type#, ts.ts#, ts.name, ts.blocksize, f.file#, s.block#, s.blocks * ts.blocksize, s.blocks, s.extents, s.iniexts * ts.blocksize, decode(bitand(ts.flags, 3), 1, to_number(NULL), s.extsize * ts.blocksize), s.minexts, s.maxexts, decode(bitand(ts.flags, 3), 1, to_number(NULL), s.extpct), decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.lists, 0, 1, s.lists)), decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.groups, 0, 1, s.groups)), s.file#, s.cachehint, NVL(s.spare1,0), o.dataobj# from sys.user$ u, sys.obj$ o, sys.ts$ ts, sys.sys_objects so, sys.seg$ s, sys.file$ f where s.file# = so.header_file and s.block# = so.header_block and s.ts# = so.ts_number and s.ts# = ts.ts# and o.obj# = so.object_id and o.owner# = u.user# and s.type# = so.segment_type_id and o.type# = so.object_type_id and s.ts# = f.ts# and s.file# = f.relfile# select u.name, un.name, NULL, decode(s.type#, 1, ‘ROLLBACK’, 10, ‘TYPE2 UNDO’), s.type#, ts.ts#, ts.name, ts.blocksize, f.file#, s.block#, s.blocks * ts.blocksize, s.blocks, s.extents, s.iniexts * ts.blocksize, s.extsize * ts.blocksize, s.minexts, s.maxexts, s.extpct, decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.lists, 0, 1, s.lists)), decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.groups, 0, 1, s.groups)), s.file#, s.cachehint, NVL(s.spare1,0), un.us# from sys.user$ u, sys.ts$ ts, sys.undo$ un, sys.seg$ s, sys.file$ f where s.file# = un.file# and s.block# = un.block# and s.ts# = un.ts# and s.ts# = ts.ts# and s.user# = u.user# and s.type# in (1, 10) and un.status$ != 1 and un.ts# = f.ts# and un.file# = f.relfile# union all select u.name, to_char(f.file#) || ‘.’ || to_char(s.block#), NULL, decode(s.type#, 2, ‘DEFERRED ROLLBACK’, 3, ‘TEMPORARY’, 4, ‘CACHE’, 9, ‘SPACE HEADER’, ‘UNDEFINED’), s.type#, ts.ts#, ts.name, ts.blocksize, f.file#, s.block#, s.blocks * ts.blocksize, s.blocks, s.extents, s.iniexts * ts.blocksize, decode(bitand(ts.flags, 3), 1, to_number(NULL), s.extsize * ts.blocksize), s.minexts, s.maxexts, decode(bitand(ts.flags, 3), 1, to_number(NULL), s.extpct), decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.lists, 0, 1, s.lists)), decode(bitand(ts.flags, 32), 32, to_number(NULL), decode(s.groups, 0, 1, s.groups)), s.file#, s.cachehint, NVL(s.spare1,0), s.hwmincr from sys.user$ u, sys.ts$ ts, sys.seg$ s, sys.file$ f where s.ts# = ts.ts# and s.user# = u.user# and s.type# not in (1, 5, 6, 8, 10) and s.ts# = f.ts# and s.file# = f.relfile# SQL> select text from dba_views where view_name=’SYS_OBJECTS’; TEXT -------------------------------------------------------------------------------------- select decode(bitand(t.property, 8192), 8192, ‘NESTED TABLE’, ‘TABLE’), 2, 5, t.obj#, t.file#, t.block#, t.ts# from sys.tab$ t where bitand(t.property, 1024) = 0 /* exclude clustered tables */ union all select ‘TABLE PARTITION’, 19, 5, tp.obj#, tp.file#, tp.block#, tp.ts# from sys.tabpart$ tp union all select ‘CLUSTER’, 3, 5, c.obj#, c.file#, c.block#, c.ts# from sys.clu$ c union all select decode(i.type#, 8, ‘LOBINDEX’, ‘INDEX’), 1, 6, i.obj#, i.file#, i.block#, i.ts# from sys.ind$ i where i.type# in (1, 2, 3, 4, 6, 7, 8, 9) union all select ‘INDEX PARTITION’, 20, 6, ip.obj#, ip.file#, ip.block#, ip.ts# from sys.indpart$ ip union all select ‘LOBSEGMENT’, 21, 8, l.lobj#, l.file#, l.block#, l.ts# from sys.lob$ l union all select ‘TABLE SUBPARTITION’, 34, 5, tsp.obj#, tsp.file#, tsp.block#, tsp.ts# from sys.tabsubpart$ tsp union all select ‘INDEX SUBPARTITION’, 35, 6, isp.obj#, isp.file#, isp.block#, isp.ts# from sys.indsubpart$ isp union all select decode(lf.fragtype$, ‘P’, ‘LOB PARTITION’, ‘LOB SUBPARTITION’), decode(lf.fragtype$, ‘P’, 40, 41), 8, lf.fragobj#, lf.file#, lf.block#, lf.ts# from sys.lobfrag$ lf 因此,从以上几个视图的定义中可以看到,Oracle9i中有如下的段类型: NESTED TABLE TABLE TABLE PARTITION CLUSTER LOBINDEX INDEX INDEX PARTITION LOBSEGMENT TABLE SUBPARTITION INDEX SUBPARTITION LOB PARTITION LOB SUBPARTITION ROLLBACK TYPE2 UNDO DEFERRED ROLLBACK TEMPORARY CACHE SPACE HEADER UNDEFINED 下面我们将对每一种段类型进行一个简单的说明: TABLE:这是最常见的段类型,普通表(即非CLUSTER),没有分区,则每个表有一个类型为TABLE的段。 INDEX:这是除了TABLE之外最常见的段类型,表的普通索引,没有分区,则每个索引有一个类型为INDEX的段。除了表上的普通索引之外,INDEX CLUSTER上的索引也是INDEX段,并且在INDEX CLUSTER上必须有一个索引(HASH CLUSTER不要求建索引)。注意IOT表的段类型为INDEX段,而不是TABLE段: SQL> create table t2 ( object_id number primary key,object_name varchar2(100)) 2 organization index; SQL> select owner,segment_type,segment_name,header_file,header_block from dba_segments where segment_name=’T2′; 未选定行 SQL> select index_name from user_indexes where table_name=’T2′; INDEX_NAME ------------------------------ SYS_IOT_TOP_29668 SQL> select owner,segment_type,segment_name from dba_segments where segment_name=’SYS_IOT_TOP_29668′; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- --------------- ---------------------------------------- SYS INDEX SYS_IOT_TOP_29668 注意IOT表的溢出段是TABLE类型的段: SQL> create table iot 2 ( x int, 3 y date, 4 z varchar2(2000), 5 constraint iot_pk primary key (x) 6 ) 7 organization index 8 pctthreshold 10 9 overflow; 表已创建。 SQL> select owner,segment_type,segment_name from dba_segments where owner=’TEST’; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- --------------- ---------------------------------------- TEST TABLE SYS_IOT_OVER_29670 TEST INDEX IOT_PK TABLE PARTITION和TABLE SUBPARTITION:表分区,每个分区或子分区都有一个段。 INDEX PARTITION和INDEX SUBPARTITION:索引分区,每个分区或子分区都有一个段。 CLUSTER:每个CLUSTER有一个CLUSTER段。一个CLUSTER中可以存储一个或多个表。由于CLUSTER不能分区,所以没有CLUSTER PARTITION这样的段。 LOBINDEX:表的每个LOB字段,有一个LOBINDEX段。注意对于分区表的LOB字段,每个分区上的LOB字段均会有LOBINDEX段,但是段类型为INDEX PARTITION或INDEX SUBPARTITION,这是一个特殊情况(不知道ORACLE为什么这样,从视图定义上看sys.indpart$和sys.indsubpart$没有type#字段)。 LOBSEGMENT、LOB PARTITION、LOB SUBPARTITION:表中的每个LOB字段,有LOBSEGMENT字段,如果表进行了分区,则在每个分区上相应有LOB PARTITION和LOB SUBPARTITION: SQL> create table t 2 ( id int primary key, 3 txt clob 4 ) 5 / SQL> select owner,segment_type,segment_name from dba_segments where owner=’TEST’; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- --------------- ---------------------------------------- TEST TABLE T TEST LOBINDEX SYS_IL0000029682C00002$$ TEST INDEX SYS_C002632 TEST LOBSEGMENT SYS_LOB0000029682C00002$$ 注意:虽然BFILE可以作为LOB类型进行处理,但存储没有LOBINDEX和LOBSEGMENT字段: SQL> create table t 2 ( id int primary key, 3 thefile bfile 4 ) 5 / SQL> select owner,segment_type,segment_name from dba_segments where owner=’TEST’; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- --------------- ---------------------------------------- TEST TABLE T TEST INDEX SYS_C002633 可以看到没有任何与BFILE相关的单独的段。 ROLLBACK:就是8i及以前的回滚段,在9i以及以后的版本中,即使使用了自动撤销段管理,仍然会有一个SYSTEM回滚段。 TYPE2 UNDO:这就是9i及以后的“撤销段”,跟ROLLBACK段类似。我们仍然习惯于叫回滚段。 DEFERRED ROLLBACK:延迟回滚段。如果一个表空间OFFLINE时,表空间上的对象存在活动事务,则会在SYSTEM表空间中创建延迟回滚段,以便在表空间ONLINE能够回滚: SQL> insert into t select * from dba_objects where rownum<=10; 已创建10行。 SQL> alter tablespace tools offline; 表空间已更改。 SQL> select owner,segment_type,segment_name from dba_segments where segment_type like ‘%DEF%’; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- ------------------------------ ---------------------------------------- SYS DEFERRED ROLLBACK 1.84337 TEMPORARY:临时段。除了磁盘排序产生临时段之外,临时表也会有临时段。另外,在CTAS过程中,如果SQL还没有最终完成,这个时候的表对应的段为TEMPORARY表,只有在SQL执行的最后将TEMPORARY段改为TABLE段。比如: SQL> create table t2 as select * from dba_objects; 在执行上面语句的同时,执行: SQL> select segment_type,owner,segment_name from dba_segments where segment_type=’TEMPORARY’; SEGMENT_TYPE OWNER SEGMENT_NAME ------------------ ------------------------------ -------------------------------------------- TEMPORARY SYS 1.84337 可以看到临时段,在CTAS执行完之后,我们可以看到: SQL> select segment_type,owner,segment_name from dba_segments where segment_type=’TEMPORARY’; 未选定行 SQL> select header_file,header_block from dba_segments where owner=USER and segment_name=’T2′; HEADER_FILE HEADER_BLOCK ----------- ------------ 1 84337 可以看到,之前的临时段(其段名为一个特别的名字1.84337,段头的文件号和块号),与CTAS后的表的段头一致。 另外在表和索引的MOVE、REBUILD阶段也会有临时段。所以临时段不一定是在临时表中,在普通的表空间中也可能会存在。 注意在排序段和临时表的段在并没有在DBA_SEGMENTS视图,而是在V$TEMPSEG_USAGE视图中。 CACHE:这是一个特殊的段,为Oracle的自举(bootstrap)段。 SQL> select owner,segment_type,segment_name,header_file,header_block from dba_segments where segment_type=’CACHE’; OWNER SEGMENT_TYPE SEGMENT_NAME HEADER_FILE HEADER_BLOCK ---------- --------------- --------------- ----------- ------------ SYS CACHE 1.833 1 833 我们通过DUMP数据文件头可以发现: FILE HEADER: Software vsn=153092096=0×9200000, Compatibility Vsn=134217728=0×8000000 Db ID=2968647772=0xb0f1f85c, Db Name=’XJ’ Activation ID=0=0×0 Control Seq=761=0×2f9, File size=128000=0×1f400 File Number=1, Blksiz=4096, File Type=3 DATA Tablespace #0 - SYSTEM rel_fn:1 Creation at scn: 0×0000.00000009 05/12/2002 16:20:42 Backup taken at scn: 0×0000.00000000 01/01/1988 00:00:00 thread:0 reset logs count:0×26ce9ece scn: 0×0000.000a65e0 recovered at 07/19/2008 21:23:10 status:0×4 root dba:0×00400341 chkpt cnt: 272 ctl cnt:271 root dba转换为文件号和块号则为1.833,正好是类型为CACHE的段头。Oracle通过文件号为1的文件头的root dba定位到自举对象,然后得到obj$等核心对象所在位置,来进行启动。 NESTED TABLE:嵌套表的段,以面举例子说明: SQL> create or replace type emp_type 2 as object 3 (empno number(4), 4 ename varchar2(10), 5 job varchar2(9), 6 mgr number(4) 7 ); 8 / 类型已创建。 SQL> create or replace type emp_tab_type 2 as table of emp_type; 3 / 类型已创建。 SQL> create table dept_and_em 2 (deptno number(2) primary key, 3 dname varchar2(14), 4 loc varchar2(13), 5 emps emp_tab_type, 6 emps2 emp_tab_type 7 ) 8 nested table emps store as emps_nt 9 nested table emps2 store as emps_nt2; 表已创建。 SQL> select owner,segment_type,segment_name from dba_segments where owner=’TEST’; OWNER SEGMENT_TYPE SEGMENT_NAME ---------- --------------- ---------------------------------------- TEST NESTED TABLE EMPS_NT TEST NESTED TABLE EMPS_NT2 TEST TABLE DEPT_AND_EM TEST INDEX SYS_C002629 TEST INDEX SYS_C002630 TEST INDEX SYS_C002631 这里看到有两个类型为NESTED TABLE的段。另外除了主键之外,每个NESTED TABLE字段上还有一个索引(实际上是每个NESTED TABLE字段对应一具隐含字段,上面建有索引)。 (责任编辑:admin) |