到成都工作以来,最漫长的一次出差。为了处理一个故障,已经出差10来天了,有达到半个月的趋势。不可控的因素,导致这么长时间的出差,虽然比项目实施出差的时间短,但以我们这种工作性质来说算是比较长的了。
看看什么时候会再次打破这个记录。
到成都工作以来,最漫长的一次出差。为了处理一个故障,已经出差10来天了,有达到半个月的趋势。不可控的因素,导致这么长时间的出差,虽然比项目实施出差的时间短,但以我们这种工作性质来说算是比较长的了。
看看什么时候会再次打破这个记录。
下面一条SQL能够使用索引吗?
select object_id,object_name,object_type from t1 where object_id is null;
有人会说,索引不存储null值,所以这个SQL不会使用索引;也有人会说,能够使用索引啊,只要在object_id列上建位图索引就可以使用索引了,另外对于CLUSTER表的KEY列,null值也可以存储在索引中(也就是能够进行索引)。
本文要探讨的是,null值不能进行索引的真正含义:
实际上对于null值,除了位图索引、CLUSTER表的KEY列,也是有可能索引的。那就是复合索引,也就是多列索引。对于普通的索引,null值不能进行索引的正确理解应该是,对于某一行,索引的所有列的值都是null值时,该行才不能被索引。
那么对于上面的SQL语句,我们就可以想办法让它走索引。下面举例说明:
SQL> desc t1
名称 是否为空? 类型
----------------------------------------- -------- --------------
OWNER VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(18)
CREATED DATE
LAST_DDL_TIME DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)SQL> create index t1_idx on t1(object_id,object_name);
SQL> analyze table t1 compute statistics for table for all indexes for all indexed columns;表已分析。
SQL> select object_id,object_name,object_type from t1 where object_id is null;OBJECT_ID OBJECT_NAME OBJECT_TYPE
---------- ------------------------------ ------------------------------
XTY DATABASE LINKExecution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=38)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=3 Card=1 Bytes
=38)2 1 INDEX (RANGE SCAN) OF 'T1_IDX' (NON-UNIQUE) (Cost=2 Card
=1)
我们可以看到,这个SQL语句走了我们建的那个索引T1_IDX。
然而,如果我们把object_name列改为允许NULL值,那么情况就发生了变化:
SQL>alter table t1 modify (object_name null);
SQL> select object_id,object_name,object_type from t1 where object_id is null;OBJECT_ID OBJECT_NAME OBJECT_TYPE
---------- ------------------------------ ------------------------------
XTY DATABASE LINKExecution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=128 Card=1 Bytes=38)
1 0 TABLE ACCESS (FULL) OF 'T1' (Cost=128 Card=1 Bytes=38)
把object_name列改为允许NULL值后,object_id和object_name列 有可能同时为NULL值,这个时候就存在着不被索引的行(就是有可能存在object_id值为null的行没有被索引),这样就只能走全表扫描了。
我们也有一种更简便的方法,不需要与其他列建立复合索引,而是与一个常量值建立复合索引:
SQL> create index t1_idx on t1(object_id,0);
SQL> analyze table t1 compute statistics for table for all indexes for all indexed columns;
SQL> explain plan for select object_id,object_name,object_type from t1 where object_id is null;
已解释。
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 81 | 3 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 81 | 3 |
|* 2 | INDEX RANGE SCAN | T1_IDX | 1 | | 2 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------2 - access("T1"."OBJECT_ID" IS NULL)
Note: cpu costing is off
引申开来,如果有类似于col_name is null这样的条件的SQL语句,希望能够使用索引,那么将col_name与其他NOT NULL的列或一个常量值建一个复合索引,也是一个可能的选择。
大家在管理ORACLE数据库时,通常使用PROFILE对用户密码设置期限,但是需要注意应用系统连接的用户,对于密码期限设置,应谨慎处理。
首先我们看看怎么样为用户设置密码有效期:
在测试例子中,我们使用TEST用户进行测试,密码为TEST,先看看用户的状态。
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';
ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
-------------- ---------- ----------- ------------------- -------
OPEN 2008-03-27 15:29:18 DEFAULTSQL> select ctime,ptime,exptime,ltime,spare6 from user$ where name='TEST';
CTIME PTIME EXPTIME LTIME SPARE6
------------------- ------------------- ------------------- ------------------- -------------------
2008-03-27 15:29:18 2008-03-27 15:29:18
在user$数据字典中,有几个字段是dba_users中看不到的。比如PTIME(应该就是密码设置或修改的时间),这里PTIME=CREATED(因为用户创建后没有改变过密码)
下面我们将创建profile,将密码有效期设置为10天,并将用户TEST的PROFILE设置为创建的test_profile:
SQL> create profile test_profile limit password_life_time 10 password_grace_time 0;
配置文件已创建
SQL> alter user test profile test_profile;
用户已更改。
再看看用户数据:
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';
ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
------------------------------ ------------------- ------------------- ------------------- ------------
OPEN 2008-04-06 15:29:18 2008-03-27 15:29:18 TEST_PROFILESQL> select ctime,ptime,exptime,ltime,spare6 from user$ where name='TEST';
CTIME PTIME EXPTIME LTIME SPARE6
------------------- ------------------- ------------------- ------------------- -------------------
2008-03-27 15:29:18 2008-03-27 15:29:18
注意到除了PROFILE列从DEFAULT变为了TEST_PROFILE,EXPIRY_DATE改变了,正好是PTIME+10。注意在USER$表中,EXPTIME为空,DBA_USERS中的EXPIRY_TIME是通过PTIME和PROFILE计算出来的。因此EXPIRY_TIME为密码将要到期的时间。
现在为用户设置好了PROFILE,新开一个SQLPLUS会话,用TEST用户登录:
SQL> connect test/test
ERROR:
ORA-28001: the password has expired更改test的口令
新口令:
这个时候可以修改用户的密码。但是如果是应用软件没有对ORA-28001错误进行处理,则不能进行连接。这个时候我们看看用户的状态:
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';
ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
------------------------------ ------------------- ------------------- ------------------- ------------
EXPIRED 2008-03-27 15:29:18 TEST_PROFILE
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
------------------------------ ------------------- ------------------- ------------------- ------------
EXPIRED 2008-03-27 15:29:18 TEST_PROFILE
可以看到用户状态为EXPIRED。这个状态是记录在数据字典USER$中的,如果此时把用户的PROFILE改回为DEFAULT,这个状态仍然不会改变。
SQL> alter user test profile default;
用户已更改。
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';
ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
------------------------------ ------------------- ------------------- ------------------- ------------
EXPIRED 2008-03-27 15:29:18 DEFAULT
用户状态仍然为EXPIRED。这个时候,如果应用连接不上数据库,只有DBA手工干预了。对于状态为LOCKED的用户,使用alter user user_name account unlock即可。对于EXPIRED状态的用户,没有UNEXPIRE的命令,只有通过修改用户密码来重设状态:
SQL> alter user test identified by test;
用户已更改。
SQL> select account_status,lock_date,expiry_date,created,profile from dba_users where username='TEST';
ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE CREATED PROFILE
------------------------------ ------------------- ------------------- ------------------- ------------
OPEN 2008-03-27 15:29:18 DEFAULT可以看到用户状态已经恢复正常。
SQL> select ctime,ptime,exptime,ltime,spare6 from user$ where name='TEST';
CTIME PTIME EXPTIME LTIME SPARE6
------------------- ------------------- ------------------- ------------------- ------------------
2008-03-27 15:29:18 2008-08-13 23:16:42
用户的密码设置时间也发生了变化。
如果在某些情况下,不知道用户的密码,可以通过下面的办法来设置密码:
SQL> select password from dba_users where username='TEST';
PASSWORD
------------------------------
7A0F2B316C212D67SQL> alter user test identified by values '7A0F2B316C212D67';
用户已更改。
总结:对于为用户设置了密码有效期限的用户,应用软件应能够处理ORA-28001错误,或者DBA应定期对密码进行重设。否则不要为用户密码设置期限,当然对于DBA帐号,为安全起见,通过PROFILE强制要求用户定期修改密码,并且可以要求每次使用的密码不能使用以前使用的密码。
虽然大部分时候都是在用Oracle9i,就算用10g,新特性也用得不多,但现在连11g都出来一年了,再这样下去就成老古董啦。所以如今从头把concepts来看,不过这次是10g的版本。数年之前,曾经看过两遍8i的concepts,9i的concepts也读过两遍,看来这10g的concepts只需要一遍就够了。
Oracle的经典书籍何其多,我也仔细看过数本,但我觉得最实在的还是Oracle的官方文档。不管怎么忙,一天至少要看10页,不是简单的看,而是要真正理解。希望从concept这本最经典的书中挖掘出以往不曾注意到的价值。
在上一篇文章(Oracle的段类型 Part I)中,我们得到了Oracle9i中所有的段类型,下面我们将对每一种段类型进行一个简单的说明:
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=0x9200000, Compatibility Vsn=134217728=0x8000000
Db ID=2968647772=0xb0f1f85c, Db Name='XJ'
Activation ID=0=0x0
Control Seq=761=0x2f9, File size=128000=0x1f400
File Number=1, Blksiz=4096, File Type=3 DATA
Tablespace #0 - SYSTEM rel_fn:1
Creation at scn: 0x0000.00000009 05/12/2002 16:20:42
Backup taken at scn: 0x0000.00000000 01/01/1988 00:00:00 thread:0
reset logs count:0x26ce9ece scn: 0x0000.000a65e0 recovered at 07/19/2008 21:23:10
status:0x4 root dba:0x00400341 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字段对应一具隐含字段,上面建有索引)。
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