表空间存储参数设置 ~~~~~~~~~~~~~~ create tablespace local datafile '/tmp/local.dbf' size 10M default storage (initial 100K next 1024K maxextents 120 pctincrease 0); SQL> SELECT Tablespace_Name, 2 Extent_Management, 3 Segment_Space_Management, 4 Allocation_Type, 5 Initial_Extent, 6 Next_Extent 7 FROM dba_tablespaces 8 WHERE Tablespace_Name IN ('TEST_TBS','LOCAL'); TABLESPACE_NAME EXTENT_MAN SEGMEN ALLOCATIO INITIAL_EXTENT NEXT_EXTENT ------------------------------ ---------- ------ --------- -------------- ----------- LOCAL LOCAL MANUAL SYSTEM 65536 TEST_TBS LOCAL MANUAL SYSTEM 65536 --没有指定区管理方式,但是设置了默认存储,这里将使用是 默认的LOCAL管理方式 MSSM AUTOALLOCATION(initial=64k,next=失效) SQL> create tablespace local1 datafile '/tmp/local1.dbf' size 10M extent management local default storage (initial 100K next 1024K maxextents 120 pctincrease 0); 2 3 4 5 create tablespace local1 * ERROR at line 1: ORA-25143: default storage clause is not compatible with allocation policy 你不能在本地管理的统一管理&自动分配管理下设置默认存储 如果是本地管理,但是是手动段管理,那么你可以在该表空间下创建对象时指定PCTFREE,PCTUSED 字典管理表空间 ~~~~~~~~~~~~~~ SQL> create tablespace test_dt 2 datafile '/tmp/test_dt.dbf' size 1m reuse 3 autoextend on next 1m 4 extent management dictionary 5 / create tablespace test_dt * ERROR at line 1: ORA-12913: Cannot create dictionary managed tablespace create table t1 ( x number ) tablespace local; SQL> exec dbms_space_admin.tablespace_migrate_from_local('LOCAL'); BEGIN dbms_space_admin.tablespace_migrate_from_local('LOCAL'); END; * ERROR at line 1: ORA-12914: Cannot migrate tablespace to dictionary managed type ORA-06512: at "SYS.DBMS_SPACE_ADMIN", line 0 ORA-06512: at line 1 SQL> alter tablespace local read only; Tablespace altered. exec dbms_space_admin.tablespace_migrate_from_local('LOCAL'); ERROR at line 1: ORA-12914: Cannot migrate tablespace to dictionary managed type ORA-06512: at "SYS.DBMS_SPACE_ADMIN", line 0 ORA-06512: at line 1 SQL> exec dbms_space_admin.tablespace_migrate_from_local('SYSTEM'); BEGIN dbms_space_admin.tablespace_migrate_from_local('SYSTEM'); END; * ERROR at line 1: ORA-03251: Cannot issue this command on SYSTEM tablespace ORA-06512: at "SYS.DBMS_SPACE_ADMIN", line 0 ORA-06512: at line 1 create table test_dict (chr char(2000)) tablesapce testing; insert into test_dict select 'test' from dba_objects where rownum <=17; col Segment_Name format a20 select Segment_Name,Extent_Id,blocks, bytes/1024/1024 sum_blks from user_extents where segment_name = 'TEST_DICT'; 1 create table t 2 storage( initial 64k next 64k pctincrease 0 ) 3 tablespace testing 4 as 5 select * from all_objects where 1=0; variable n number; exec :n := 5; 1 insert into t 2 select * from all_objects where rownum < :n; set autotrace traceonly statistics; exec :n := 99999 1 insert into t 2 select * from all_objects where rownum < :n; set autotrace off 本地管理表空间 ~~~~~~~~~~~~~~ 1 create tablespace testing_lmt 2 datafile '/tmp/testing_lmt.dbf' size 1m reuse 3 autoextend on next 1m 4 extent management local 5 uniform size 64k 6 / create table test_lmt (chr char(2000)) tablespace testing_lmt; insert into test_lmt select ' ' from dba_objects where rownum <=17; col Segment_Name format a20 select Segment_Name,Extent_Id,blocks, bytes/1024/1024 sum_blks from user_extents where segment_name = 'TEST_LMT'; commit; drop table t; 1 create table t 2 tablespace testing_lmt 3 as 4 select * from all_objects where 1=0; variable n number; exec :n := 5; 1 insert into t 2 select * from all_objects where rownum < :n; set autotrace traceonly statistics; exec :n := 99999 1 insert into t 2 select * from all_objects where rownum < :n; set autotrace off 查看表空间使用情况 ~~~~~~~~~~~~~~~~ 表空间 select nvl(b.tablespace_name, nvl(a.tablespace_name,'UNKOWN')) name, kbytes_alloc kbytes, kbytes_alloc-nvl(kbytes_free,0) used, nvl(kbytes_free,0) free, ((kbytes_alloc-nvl(kbytes_free,0))/ kbytes_alloc)*100 pct_used, nvl(largest,0) largest from ( select sum(bytes)/1024 Kbytes_free, max(bytes)/1024 largest, tablespace_name from sys.dba_free_space group by tablespace_name ) a, ( select sum(bytes)/1024 Kbytes_alloc, tablespace_name from sys.dba_data_files group by tablespace_name )b where a.tablespace_name (+) = b.tablespace_name 表空间测试 ~~~~~~~~~~~~~~ create tablespace test_tbs datafile '/tmp/test_tbs.dbf' size 1m reuse; --没有任何区分配方式和段管理方式 SQL> SELECT Tablespace_Name, 2 Extent_Management, 3 Segment_Space_Management, 4 Allocation_Type, 5 Initial_Extent, 6 Next_Extent 7 FROM dba_tablespaces 8 WHERE Tablespace_Name IN ('TEST_TBS','SYSTEM'); TABLESPACE_NAME EXTENT_MAN SEGMEN ALLOCATIO INITIAL_EXTENT NEXT_EXTENT ------------------------------ ---------- ------ --------- -------------- ----------- SYSTEM LOCAL MANUAL SYSTEM 65536 TEST_TBS LOCAL MANUAL SYSTEM 65536 我们看到SYSTEM是本地管理方式 9I默认不设置任何区分配方式和段管理方式时是 LOCAL MSSM AUTOALLOCATION(initial=64k,next=失效) SQL> COL FILE_NAME FORMAT A30 SQL> SELECT FILE_NAME, BYTES, USER_BYTES ,AUTOEXTENSIBLE 2 FROM dba_data_files 3 WHERE Tablespace_Name ='TEST_TBS'; FILE_NAME BYTES USER_BYTES AUT ------------------------------ ---------- ---------- --- /tmp/test_tbs.dbf 1048576 983040 NO 1048576 - 983040 = 64K 这64K是文件头保留区域 1048576 + 63*1024 = 1113088 SQL> SELECT tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 FROM dba_free_space 6 WHERE tablespace_name = 'TEST_TBS' 7 / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 9 983040 120 SQL> alter database datafile '/tmp/test_tbs.dbf' resize 1113088; Database altered. 这样,在本地管理统一管理的话可能用不到这63K,浪费了空间 本地管理系统分配区测试 ~~~~~~~~~~~~~~~ SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 9 983040 120 初始时,数据文件里没有对象时,在块大小小于16K的时候,文件头保留64K的数据,用于本地区管理 所以空闲区的第1个块号是9号,共可以存放120块 SQL>create table t_t1 ( x int ) 2 storage ( initial 1k next 1k pctincrease 50 ) 3 tablespace test_tbs; Table created. SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 SQL> SELECT Segment_Name,Initial_Extent,Min_Extents,Next_Extent FROM dba_segments WHERE segment_name = 'T_T1'; SEGMENT_NAME INITIAL_EXTENT MIN_EXTENTS NEXT_EXTENT --------------------- -------------- ----------- ----------- T_T1 16384 1 我们看到initial 1k,但实际上用了表空间的最小的区INITIAL至少是2个块=16K 这里看不到NEXT EXTENT SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 17 917504 112 --创建任何一个对象,都需要第1个区,所以,第2组8块被T_T1使用了,所以空闲块从17开始 SQL> insert into t_t1 select rownum from dba_objects; 28516 rows created. SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 我们看到没有提交就已经分配了6个8块64K的区 SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 SQL> / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 57 589824 72 我们看到空闲区是从49+8=57的位置 SQL> commit; Commit complete. SQL> create table t_t2 ( x int ) pctfree 0 initrans 1 2 storage ( initial 1k next 1k pctincrease 50 ) 3 tablespace test_tbs; Table created. SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 T_T2 TEST_TBS 57 8 65536 7 rows selected. 这里T_T2从57开始分配了8块64K的区 SQL> insert into t_t2 select rownum from dba_objects; 28516 rows created. SQL> commit; Commit complete. SQL> commit; Commit complete. SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 T_T2 TEST_TBS 57 8 65536 T_T2 TEST_TBS 65 8 65536 T_T2 TEST_TBS 73 8 65536 T_T2 TEST_TBS 81 8 65536 T_T2 TEST_TBS 89 8 65536 11 rows selected. 我们看到同样28516行记录,T_T1用了6个区,T_T2用了5个区,为什么呢 SQL> SELECT TABLE_NAME,PCT_FREE,PCT_USED FROM USER_TABLES WHERE TABLE_NAME IN ('T_T1','T_T2') 2 / TABLE_NAME PCT_FREE PCT_USED ------------------------------ ---------- ---------- T_T1 10 40 T_T2 0 40 原来T_T2更精简,因为PCTFREE=0 SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 SQL> / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 97 262144 32 现在空闲空间只剩下32块了,正好4个区 SQL> delete from t_t1 where rownum <=28516/5; 5703 rows deleted. commit; SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 T_T2 TEST_TBS 57 8 65536 T_T2 TEST_TBS 65 8 65536 T_T2 TEST_TBS 73 8 65536 T_T2 TEST_TBS 81 8 65536 T_T2 TEST_TBS 89 8 65536 11 rows selected. 我们看到删除T_T1,空间仍然没有腾出来. 我们来单独分配4个区,使得文件填满,没有空闲分区 SQL> alter table t_t1 allocate extent; Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 T_T1 TEST_TBS 97 8 65536 <<- T_T1 TEST_TBS 105 8 65536 <<- T_T1 TEST_TBS 113 8 65536 <<- T_T1 TEST_TBS 121 8 65536 <<- T_T2 TEST_TBS 57 8 65536 T_T2 TEST_TBS 65 8 65536 T_T2 TEST_TBS 73 8 65536 T_T2 TEST_TBS 81 8 65536 T_T2 TEST_TBS 89 8 65536 新增4个区 SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 / no rows selected 文件没有空闲空间 --我们看到数据文件没有空间 SQL> alter database datafile '/tmp/test_tbs.dbf' resize 12m; Database altered. SQL> col file_name format a30 SQL> SELECT FILE_NAME, BYTES, USER_BYTES ,AUTOEXTENSIBLE 2 FROM dba_data_files 3 WHERE Tablespace_Name ='TEST_TBS'; FILE_NAME BYTES USER_BYTES AUT ------------------------------ ---------- ---------- --- /tmp/test_tbs.dbf 12582912 12517376 NO SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 SQL> / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 129 11534336 1408 多出了1408个块 SQL> INSERT INTO T_T2 SELECT ROWNUM FROM DBA_OBJECTS; 28516 rows created. SQL> INSERT INTO T_T2 SELECT * FROM T_T2; 57032 rows created. SQL> set pagesize 100 SQL> SELECT SEGMENT_NAME, 2 TABLESPACE_NAME, 3 BLOCK_ID, 4 BLOCKS, 5 BYTES 6 FROM dba_extents 7 WHERE TABLESPACE_NAME = 'TEST_TBS'; SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T1 TEST_TBS 9 8 65536 T_T1 TEST_TBS 17 8 65536 T_T1 TEST_TBS 25 8 65536 T_T1 TEST_TBS 33 8 65536 T_T1 TEST_TBS 41 8 65536 T_T1 TEST_TBS 49 8 65536 T_T1 TEST_TBS 97 8 65536 T_T1 TEST_TBS 105 8 65536 T_T1 TEST_TBS 113 8 65536 T_T1 TEST_TBS 121 8 65536 T_T2 TEST_TBS 57 8 65536 T_T2 TEST_TBS 65 8 65536 T_T2 TEST_TBS 73 8 65536 T_T2 TEST_TBS 81 8 65536 T_T2 TEST_TBS 89 8 65536 T_T2 TEST_TBS 129 8 65536 T_T2 TEST_TBS 137 8 65536 T_T2 TEST_TBS 145 8 65536 T_T2 TEST_TBS 153 8 65536 T_T2 TEST_TBS 161 8 65536 T_T2 TEST_TBS 169 8 65536 T_T2 TEST_TBS 177 8 65536 T_T2 TEST_TBS 185 8 65536 T_T2 TEST_TBS 193 8 65536 T_T2 TEST_TBS 201 8 65536 T_T2 TEST_TBS 209 8 65536 T_T2 TEST_TBS 265 128 1048576 <<===T_T2的第17个区就自动扩展成128个块,1M 但是注意,该区需要16个位图来表示这个区 SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 SQL> / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 217 393216 48 TEST_TBS 393 9371648 1144 T_T2扩展到第16个区一直分配到217,在分配第17个区时需要扫描128个块的区,这时候没有直接从217块开始分配,而是预留给48个块 因为48块是适合小的区,防备将来新增小表 从217 + 48 = 265 到393分配给T_T2 SQL> COMMIT; Commit complete. create table t_t3 ( x int ) pctfree 0 storage ( initial 1k next 1k pctincrease 50 ) tablespace test_tbs; SQL> SELECT SEGMENT_NAME, TABLESPACE_NAME, BLOCK_ID, BLOCKS, BYTES FROM dba_extents WHERE TABLESPACE_NAME = 'TEST_TBS' AND SEGMENT_NAME = 'T_T3' 2 3 4 5 6 7 8 / SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T3 TEST_TBS 217 8 65536 我们看到新表T_T3是从空出来的48块中进行分配 SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 225 327680 40 TEST_TBS 393 9371648 1144 我们模拟INERT T_T2把1144块填充,大概需要扩展9次 128*8=1024 SQL> INSERT INTO T_T2 SELECT * FROM T_T2; 114064 rows created. SQL> commit; Commit complete. SQL> INSERT INTO T_T2 SELECT * FROM T_T2; 228128 rows created. SQL> INSERT INTO T_T2 SELECT * FROM T_T2; 456256 rows created. SQL> commit; Commit complete. SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 SQL> / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 225 327680 40 TEST_TBS 1417 983040 120 SQL> alter table t_t3 allocate extent; --15下,正好用完120,因为15*8=120 Table altered. SQL> SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> / Table altered. SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_TBS' 7 / TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_TBS 1497 327680 40 SQL> SELECT SEGMENT_NAME, TABLESPACE_NAME, BLOCK_ID, BLOCKS, BYTES FROM dba_extents WHERE TABLESPACE_NAME = 'TEST_TBS' AND SEGMENT_NAME = 'T_T3'; 2 3 4 5 6 7 SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- T_T3 TEST_TBS 217 8 65536 T_T3 TEST_TBS 225 8 65536 T_T3 TEST_TBS 233 8 65536 T_T3 TEST_TBS 241 8 65536 T_T3 TEST_TBS 249 8 65536 T_T3 TEST_TBS 257 8 65536 T_T3 TEST_TBS 1417 8 65536 T_T3 TEST_TBS 1425 8 65536 T_T3 TEST_TBS 1433 8 65536 T_T3 TEST_TBS 1441 8 65536 T_T3 TEST_TBS 1449 8 65536 T_T3 TEST_TBS 1457 8 65536 T_T3 TEST_TBS 1465 8 65536 T_T3 TEST_TBS 1473 8 65536 T_T3 TEST_TBS 1481 8 65536 T_T3 TEST_TBS 1489 8 65536 16个区了,下一个区就是128块 SQL> alter table t_t3 allocate extent; alter table t_t3 allocate extent * ERROR at line 1: ORA-01653: unable to extend table SYS.T_T3 by 128 in tablespace TEST_TBS 提示128 in tablespace TEST_TBS GIG CUMGIG EXTENTS MBYTES START_EXT END_EXT EXTENTS ---------- ---------- ---------- ---------- ---------- ---------- ---------- 9.9375 .000976563 342 .0625 0 15 16 9.9375 .0625 342 1 16 78 63 9.9375 1 342 8 79 198 120 9.9375 9.9375 342 64 199 341 143 二、本地自动extent管理方式 前面讲述了表空间的统一分配,那么,再看看表空间在自动分配情况下是否有碎片。在自动分配的本地管理的表空间中,区间尺寸可能由64KB、1MB、8MB、64MB甚至是256MB等尺寸组成。但是不管尺寸有多大,都有一个通用尺寸64KB,所以64KB就是该表空间的位图(bit)大小。 在这种方式下,每个位图(1或0)只代表64Kb的基本空间,而不代表统一管理方式中的一个extent大小(uniform size)。 一定程度上存在跟字典管理中同样的问题。如一个extent大小可以等于多个位图,如果表空间中存在很多比较小的连续空间,如64Kb、128kb,那么申请比较大的extent的时候,一样也是申请不了的。 所以,在用户的表空间中,不建议使用自动分配,还是采用统一尺寸分配。 比如,有一个表空间,上面有十个数据文件,每个数据文件还剩500MB的空间,但是,现在有一个段突然需要分配512MB的空间,一样会导致空间分配失败。 不过,自动分配也不是一无是处。应当看到,系统表空间就是自动分配,而且还非常适合,因为: 1,每个对象都不大,但是对象非常多,这样的情况下,如果统一分配,可能造成空间的浪费。而自动分配的基数是64KB,比较节省空间。 2,这些对象基本都不被删除与添加,也就是结构比较稳定。 3,新创建的对象,不指定初始大小,方便使用空间空间。 如果你的业务也满足如上的条件,其实,也完全可以使用自动分配,因为这样可以节省很多空闲空间,也不会有空间碎片产生。 字典管理碎片测试 SQL> select * 2 from dba_free_space 3 where bytes <= ( select min(next_extent) 4 from dba_segments 5 where tablespace_name = dba_free_space.tablespace_name) 6 and tablespace_name = 'TEST_TBS' 7 order by block_id; SELECT a.SEGMENT_NAME, a.SEGMENT_TYPE, a.TABLESPACE_NAME, a.OWNER FROM DBA_SEGMENTS a WHERE a.NEXT_EXTENT >= (SELECT MAX(b.BYTES) FROM DBA_FREE_SPACE b WHERE b.TABLESPACE_NAME = a.TABLESPACE_NAME) OR a.EXTENTS = a.MAX_EXTENTS OR a.EXTENTS = 'data_block_size' ; 本地管理区统一分配 ~~~~~~~~~~~~~~ 一、本地统一尺寸的extent管理方式: 这种管理方式下,在表空间头部的位图中,用0与1来表示未用的或者已经使用过的空间。1表示已使用,0表示未使用。 下面这个例子,先创建一个本地管理的表空间,extent大小为1MB create tablespace test_uniform datafile '/tmp/test_uniform.dbf' size 10M extent management local uniform size 1M; SQL> select tablespace_name, 2 block_id, 3 bytes, 4 blocks 5 from dba_free_space 6 where tablespace_name = 'TEST_UNIFORM'; TABLESPACE_NAME BLOCK_ID BYTES BLOCKS ------------------------------ ---------- ---------- ---------- TEST_UNIFORM 9 9437184 1152 然后创建一个表,指定初始大小与NEXT大小都是8MB SQL> create table test(x number) tablespace TEST_UNIFORM 2 storage (initial 8M next 8M); Table created. 虽然取消了NEXT参数,但是,如果指定了NEXT参数,也不会出现任何错误,只是oracle在这里忽略了这个参数。 表创建完成之后,查看他的实际大小与NEXT大小: SQL> select table_name,initial_extent,next_extent from user_tables 2 where table_name='TEST' 3 / TABLE_NAME INITIAL_EXTENT NEXT_EXTENT ------------------------------ -------------- ----------- TEST 8388608 1048576 我们这里看到NEXT_EXTENT有值,而且没有按照表的定义设置大小,而在系统自动分配区的情况下该值为空 可以看到,初始区间的确是8MB,但是,NEXT大小是1MB,并不是我们指定的8MB,那么,初始区间的8MB,到底是几个Extent呢? SELECT SEGMENT_NAME, TABLESPACE_NAME, BLOCK_ID, BLOCKS, BYTES FROM dba_extents WHERE segment_name='TEST'; SQL> 2 3 4 5 6 7 SEGMENT_NA TABLESPACE_NAME BLOCK_ID BLOCKS BYTES ---------- ------------------------------ ---------- ---------- ---------- TEST TEST_UNIFORM 9 128 1048576 TEST TEST_UNIFORM 137 128 1048576 TEST TEST_UNIFORM 265 128 1048576 TEST TEST_UNIFORM 393 128 1048576 TEST TEST_UNIFORM 521 128 1048576 TEST TEST_UNIFORM 649 128 1048576 TEST TEST_UNIFORM 777 128 1048576 TEST TEST_UNIFORM 905 128 1048576 从上图可以看到所有区还是1M来分的,即使初始区设置了8M 可以发现,实际上有8个extent,既然是8个不同的extent,那么,他们就可以是不连续的物理空间,且只需要有8个标准尺寸的1MB空间就可以了。 根据以上的原理,每个段的extent大小都等于表空间的统一尺寸大小,所以,根本不可能产生空间碎片。 不过,在统一尺寸的分配方式中,也还要注意如下两个问题: 1,不同大小的表最好设置不同大小的extent的表空间。对于几个GB的表,采用1MB的extent大小是比较合理的;如果表非常大,如 几十GB或几百GB,则可以考虑8MB、16MB、32MB甚至更大的extent尺寸。这种情况下,创建不同extent大小的表空间即可。 2,如果采用了比较大的extent大小,注意每个数据文件后面的空间浪费。如一个数据文件大小是2000MB,每个extent大小为64MB,但是,因为位图与数据文件头占了64KB,所以(2000M-64K)/64M是除不尽的,必将造成每个数据文件后面浪费差不多64MB的空间。这样的情况下,可以考虑把数据文件大小设置为2001Mb,就可以避免空间浪费了。 IOT ~~~~~~~~~~~~~ @connect / drop table iot; drop table heap; set echo on set linesize 121 clear screen create table iot ( username varchar2(30), document_name varchar2(30), other_data char(1000), constraint iot_pk primary key (username,document_name) ) organization index / create table heap ( username varchar2(30), document_name varchar2(30), other_data char(1000), constraint heap_pk primary key (username,document_name) ) / pause clear screen begin for i in 1 .. 100 loop for x in ( select username from all_users ) loop insert into heap (username,document_name,other_data) values ( x.username, x.username || '_' || i, 'x' ); insert into iot (username,document_name,other_data) values ( x.username, x.username || '_' || i, 'x' ); end loop; end loop; commit; end; / exec dbms_stats.gather_table_stats( user, 'IOT', cascade=>true ); exec dbms_stats.gather_table_stats( user, 'HEAP', cascade=>true ); pause clear screen column val format a25 select * from index_stats; pause select * from table(cols_as_rows('select * from index_stats where rownum=1')) where rownum <= 10; pause column cname format a25 column t1 format a20 column t2 format a20 clear screen set pause on select a.cname, decode( is_number(a.val),0,a.val,round(a.val,2)) t1, decode( is_number(b.val),0,b.val,round(b.val,2)) t2, case when is_number(a.val) = 1 and is_number(b.val) = 1 then to_char( decode(a.val,'0',null,round(b.val/a.val*100,2) ), '9,999.00' ) end pct from table( cols_as_rows( q'|select * from index_stats where name = 'UNCOMPRESSED_IDX' |' ) ) a, table( cols_as_rows( q'|select * from index_stats where name = 'COMPRESSED_IDX' |' ) ) b where a.cname = b.cname / set pause off 位图索引测试 ~~~~~~~~~~~~~~~~~~~ connect / set echo on drop table emp; clear screen create table emp as select * from scott.emp; create bitmap index job_idx on emp(job); pause column bits format a30 clear screen with jobs as (select distinct job from emp), emps as (select job, row_number() over (order by rowid) rn from emp), cnt as (select count(*) cnt from emp) select job, ltrim(sys_connect_by_path( bit, '-' ),'-') bits from ( select jobs.job, case when jobs.job = emps.job then '1' else '0' end bit, emps.rn from jobs, emps ) where level = (select cnt from cnt) start with rn=1 connect by prior job = job and prior rn = rn-1 / pause clear screen select ename, job from emp where ename like 'S%'; update emp set job = 'CLERK' where ename = 'SCOTT'; declare pragma autonomous_transaction; begin update emp set job = 'ANALYST' where ename = 'SMITH'; commit; end; / pause clear screen declare pragma autonomous_transaction; begin insert into emp(empno,job) values (1234,'CLERK'); commit; end; / rollback; pause 测试过程: SQL> drop table emp; drop table emp * ERROR 位于第 1 行: ORA-00942: 表或视图不存在 SQL> create table emp 2 as 3 select * 4 from scott.emp; 表已创建。 SQL> create bitmap index job_idx on emp(job); 索引已创建。 SQL> column bits format a30 SQL> with jobs as (select distinct job from emp), 2 emps as (select job, row_number() over (order by rowid) rn from emp), 3 cnt as (select count(*) cnt from emp) 4 select job, 5 ltrim(sys_connect_by_path( bit, '-' ),'-') bits 6 from ( 7 select jobs.job, 8 case when jobs.job = emps.job then '1' else '0' end bit, 9 emps.rn 10 from jobs, emps 11 ) 12 where level = (select cnt from cnt) 13 start with rn=1 14 connect by prior job = job and prior rn = rn-1 15 / JOB BITS --------- ------------------------------ ANALYST 0-0-0-0-0-0-0-1-0-0-0-0-1-0 CLERK 1-0-0-0-0-0-0-0-0-0-1-1-0-1 MANAGER 0-0-0-1-0-1-1-0-0-0-0-0-0-0 PRESIDENT 0-0-0-0-0-0-0-0-1-0-0-0-0-0 SALESMAN 0-1-1-0-1-0-0-0-0-1-0-0-0-0 SQL> select ename, job from emp where ename like 'S%'; ENAME JOB ---------- --------- SMITH CLERK SCOTT ANALYST SQL> update emp set job = 'CLERK' where ename = 'SCOTT'; 已更新 1 行。 SQL> declare 2 pragma autonomous_transaction; 3 begin 4 update emp set job = 'ANALYST' where ename = 'SMITH'; 5 commit; 6 end; 7 / declare * ERROR 位于第 1 行: ORA-00060: 等待资源时检测到死锁 ORA-06512: 在line 4 SQL> declare 2 pragma autonomous_transaction; 3 begin 4 insert into emp(empno,job) values (1234,'CLERK'); 5 commit; 6 end; 7 / declare * ERROR 位于第 1 行: ORA-00060: 等待资源时检测到死锁 ORA-06512: 在line 4 SQL> rollback; 回退已完成。 SQL> cluster的测试 ~~~~~~~~~~~~~~~~~~~ connect / set echo on drop table emp; drop table emp_heap; drop table dept; drop table dept_heap; drop cluster emp_dept_cluster; clear screen create cluster emp_dept_cluster ( deptno number(5) ) size 1024 / create index emp_dept_cluster_idx on cluster emp_dept_cluster / pause clear screen create table dept ( deptno number(5) primary key, dname varchar2(14), loc varchar2(13) ) cluster emp_dept_cluster(deptno) / create table dept_heap ( deptno number(5) primary key, dname varchar2(14), loc varchar2(13) ) / pause clear screen create table emp ( empno number primary key, ename varchar2(10), job varchar2(9), mgr number, hiredate date, sal number, comm number, deptno number(5) references dept(deptno) ) cluster emp_dept_cluster(deptno); create table emp_heap ( empno number primary key, ename varchar2(10), job varchar2(9), mgr number, hiredate date, sal number, comm number, deptno number(5) references dept_heap(deptno) ); create index emp_heap_deptno_idx on emp_heap(deptno); pause clear screen insert into dept (deptno, dname, loc ) select rownum, substr( object_name, 1, dbms_random.value( 5, 14 ) ), substr( owner, 1, dbms_random.value( 8, 13 ) ) from stage where rownum <= 10000 / insert into dept_heap (deptno, dname, loc ) select rownum, substr( object_name, 1, dbms_random.value( 5, 14 ) ), substr( owner, 1, dbms_random.value( 8, 13 ) ) from stage where rownum <= 10000 / pause clear screen insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno ) select object_id empno, substr(object_name,1,10) ename, substr(object_name,1,9) job, object_id mgr, created hiredate, data_object_id sal, data_object_id comm, mod(rownum,10000)+1 deptno from stage / insert into emp_heap (empno, ename, job, mgr, hiredate, sal, comm, deptno ) select object_id empno, substr(object_name,1,10) ename, substr(object_name,1,9) job, object_id mgr, created hiredate, data_object_id sal, data_object_id comm, mod(rownum,10000)+1 deptno from stage / pause clear screen exec dbms_stats.gather_table_stats( user, 'EMP' ); exec dbms_stats.gather_table_stats( user, 'EMP_HEAP' ); exec dbms_stats.gather_table_stats( user, 'DEPT' ); exec dbms_stats.gather_table_stats( user, 'DEPT_HEAP' ); exec dbms_stats.gather_index_stats( user, 'EMP_DEPT_CLUSTER_IDX' ); pause column PLAN_TABLE_OUTPUT format a72 truncate clear screen delete from plan_table; explain plan for select * from emp, dept where emp.deptno = dept.deptno and dept.deptno = 10 / pause clear scree select * from table(dbms_xplan.display); pause clear screen delete from plan_table; explain plan for select * from emp_heap, dept_heap where emp_heap.deptno = dept_heap.deptno and dept_heap.deptno = 10 / pause clear scree select * from table(dbms_xplan.display); pause set termout off commit; select emp.ename, dept.dname from emp, dept where emp.deptno = dept.deptno and dept.deptno = 10 / select emp_heap.ename, dept_heap.dname from emp_heap, dept_heap where emp_heap.deptno = dept_heap.deptno and dept_heap.deptno = 10 / commit; set termout on clear scree alter system flush buffer_cache; exec dbms_monitor.session_trace_enable( waits=>true ); select emp.ename, dept.dname from emp, dept where emp.deptno = dept.deptno and dept.deptno = 10 / select emp_heap.ename, dept_heap.dname from emp_heap, dept_heap where emp_heap.deptno = dept_heap.deptno and dept_heap.deptno = 10 / pause clear screen select dbms_rowid.rowid_block_number( emp.rowid ) erid, dbms_rowid.rowid_block_number( dept.rowid ) drid from emp, dept where emp.deptno = dept.deptno and dept.deptno = 10 / pause clear screen select dbms_rowid.rowid_block_number( emp_heap.rowid ) erid, dbms_rowid.rowid_block_number( dept_heap.rowid ) drid from emp_heap, dept_heap where emp_heap.deptno = dept_heap.deptno and dept_heap.deptno = 10 / pause clear screen select count(distinct rid) , count(*) from (select rowid rid from dept union all select rowid rid from emp) / select count(distinct rid) , count(*) from (select rowid rid from dept_heap union all select rowid rid from emp_heap) / pause clear screen drop table emp; drop table dept; drop table emp_heap; drop table dept_heap; drop cluster emp_dept_cluster; clear screen 测试结果: SQL> insert into dept (deptno, dname, loc ) 2 select rownum, 3 substr( object_name, 1, dbms_random.value( 5, 14 ) ), 4 substr( owner, 1, dbms_random.value( 8, 13 ) ) 5 from stage 6 where rownum <= 10000 7 / 已创建10000行。 SQL> insert into dept_heap (deptno, dname, loc ) 2 select rownum, 3 substr( object_name, 1, dbms_random.value( 5, 14 ) ), 4 substr( owner, 1, dbms_random.value( 8, 13 ) ) 5 from stage 6 where rownum <= 10000 7 / 已创建10000行。 SQL> insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno ) 2 select object_id empno, 3 substr(object_name,1,10) ename, substr(object_name,1,9) job, 4 object_id mgr, created hiredate, data_object_id sal, 5 data_object_id comm, 6 mod(rownum,10000)+1 deptno 7 from stage 8 / 已创建40707行。 SQL> insert into emp_heap (empno, ename, job, mgr, hiredate, sal, comm, deptno ) 2 select object_id empno, 3 substr(object_name,1,10) ename, substr(object_name,1,9) job, 4 object_id mgr, created hiredate, data_object_id sal, 5 data_object_id comm, 6 mod(rownum,10000)+1 deptno 7 from stage 8 / 已创建40707行。 SQL> exec dbms_stats.gather_table_stats( user, 'EMP' ); PL/SQL 过程已成功完成。 SQL> exec dbms_stats.gather_table_stats( user, 'EMP_HEAP' ); PL/SQL 过程已成功完成。 SQL> exec dbms_stats.gather_table_stats( user, 'DEPT' ); PL/SQL 过程已成功完成。 SQL> exec dbms_stats.gather_table_stats( user, 'DEPT_HEAP' ); PL/SQL 过程已成功完成。 SQL> exec dbms_stats.gather_index_stats( user, 'EMP_DEPT_CLUSTER_IDX' ); PL/SQL 过程已成功完成。 SQL> column PLAN_TABLE_OUTPUT format a72 truncate SQL> delete from plan_table; 已删除0行。 SQL> explain plan for 2 select * 3 from emp, dept 4 where emp.deptno = dept.deptno 5 and dept.deptno = 10 6 / 已解释。 SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ Plan hash value: 1728853682 ------------------------------------------------------------------------ | Id | Operation | Name | Rows | By ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 4 | | 1 | NESTED LOOPS | | 4 | | 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | |* 3 | INDEX UNIQUE SCAN | SYS_C005422 | 1 | | 4 | TABLE ACCESS CLUSTER | EMP | 4 | |* 5 | INDEX UNIQUE SCAN | EMP_DEPT_CLUSTER_IDX | 1 | PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ ------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEPT"."DEPTNO"=10) 5 - access("EMP"."DEPTNO"=10) 已选择18行。 SQL> delete from plan_table; 已删除6行。 SQL> explain plan for 2 select * 3 from emp_heap, dept_heap 4 where emp_heap.deptno = dept_heap.deptno 5 and dept_heap.deptno = 10 6 / 已解释。 SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ Plan hash value: 3849298615 ------------------------------------------------------------------------ | Id | Operation | Name | Rows | Byt ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 4 | 2 | 1 | NESTED LOOPS | | 4 | 2 | 2 | TABLE ACCESS BY INDEX ROWID| DEPT_HEAP | 1 | |* 3 | INDEX UNIQUE SCAN | SYS_C005423 | 1 | | 4 | TABLE ACCESS BY INDEX ROWID| EMP_HEAP | 4 | 1 |* 5 | INDEX RANGE SCAN | EMP_HEAP_DEPTNO_IDX | 4 | PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ ------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEPT_HEAP"."DEPTNO"=10) 5 - access("EMP_HEAP"."DEPTNO"=10) 已选择18行。 SQL> set linesize 120 SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ Plan hash value: 3849298615 ------------------------------------------------------------------------ | Id | Operation | Name | Rows | Byt ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 4 | 2 | 1 | NESTED LOOPS | | 4 | 2 | 2 | TABLE ACCESS BY INDEX ROWID| DEPT_HEAP | 1 | |* 3 | INDEX UNIQUE SCAN | SYS_C005423 | 1 | | 4 | TABLE ACCESS BY INDEX ROWID| EMP_HEAP | 4 | 1 |* 5 | INDEX RANGE SCAN | EMP_HEAP_DEPTNO_IDX | 4 | PLAN_TABLE_OUTPUT ------------------------------------------------------------------------ ------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEPT_HEAP"."DEPTNO"=10) 5 - access("EMP_HEAP"."DEPTNO"=10) 已选择18行。 SQL> set termout off SQL> commit; 提交完成。 SQL> select emp.ename, dept.dname 2 from emp, dept 3 where emp.deptno = dept.deptno 4 and dept.deptno = 10 5 / ENAME DNAME ---------- -------------- MAP_OBJECT RE$NV_LIST /c7d805c9_ RE$NV_LIST /29bb36f7_ RE$NV_LIST /ce66521c_ RE$NV_LIST /7dc9ed4e_ RE$NV_LIST SQL> select emp_heap.ename, dept_heap.dname 2 from emp_heap, dept_heap 3 where emp_heap.deptno = dept_heap.deptno 4 and dept_heap.deptno = 10 5 / ENAME DNAME ---------- -------------- MAP_OBJECT RE$NV_ /c7d805c9_ RE$NV_ /29bb36f7_ RE$NV_ /ce66521c_ RE$NV_ /7dc9ed4e_ RE$NV_ SQL> commit; 提交完成。 SQL> set termout on SQL> alter system flush buffer_cache; alter system flush buffer_cache * 第 1 行出现错误: ORA-01031: 权限不足 SQL> exec dbms_monitor.session_trace_enable( waits=>true ); PL/SQL 过程已成功完成。 SQL> select emp.ename, dept.dname 2 from emp, dept 3 where emp.deptno = dept.deptno 4 and dept.deptno = 10 5 / ENAME DNAME ---------- -------------- MAP_OBJECT RE$NV_LIST /c7d805c9_ RE$NV_LIST /29bb36f7_ RE$NV_LIST /ce66521c_ RE$NV_LIST /7dc9ed4e_ RE$NV_LIST SQL> select emp_heap.ename, dept_heap.dname 2 from emp_heap, dept_heap 3 where emp_heap.deptno = dept_heap.deptno 4 and dept_heap.deptno = 10 5 / ENAME DNAME ---------- -------------- MAP_OBJECT RE$NV_ /c7d805c9_ RE$NV_ /29bb36f7_ RE$NV_ /ce66521c_ RE$NV_ /7dc9ed4e_ RE$NV_ SQL> select dbms_rowid.rowid_block_number( emp.rowid ) erid, 2 dbms_rowid.rowid_block_number( dept.rowid ) drid 3 from emp, dept 4 where emp.deptno = dept.deptno 5 and dept.deptno = 10 6 / ERID DRID ---------- ---------- 1536 1536 1536 1536 1536 1536 1536 1536 1536 1536 SQL> select dbms_rowid.rowid_block_number( emp_heap.rowid ) erid, 2 dbms_rowid.rowid_block_number( dept_heap.rowid ) drid 3 from emp_heap, dept_heap 4 where emp_heap.deptno = dept_heap.deptno 5 and dept_heap.deptno = 10 6 / ERID DRID ---------- ---------- 2175 2151 3989 2151 4138 2151 4224 2151 4379 2151 SQL> select count(distinct rid) , count(*) 2 from (select rowid rid from dept 3 union all 4 select rowid rid from emp) 5 / COUNT(DISTINCTRID) COUNT(*) ------------------ ---------- 40707 50707 SQL> select count(distinct rid) , count(*) 2 from (select rowid rid from dept_heap 3 union all 4 select rowid rid from emp_heap) 5 / COUNT(DISTINCTRID) COUNT(*) ------------------ ---------- 50707 50707 反转索引的测试 ~~~~~~~~~~~~ connect / create or replace type str2tblType as table of varchar2(30) / create or replace function str2tbl( p_str in varchar2, p_delim in varchar2 default ',' ) return str2tblType PIPELINED as l_str long default p_str || p_delim; l_n number; begin loop l_n := instr( l_str, p_delim ); exit when (nvl(l_n,0) = 0); pipe row( ltrim(rtrim(substr(l_str,1,l_n-1))) ); l_str := substr( l_str, l_n+1 ); end loop; return; end; / set echo on column dmp format a10 column rev format a10 set linesize 100 clear screen set pause on with data as (select num, substr( dump(num,16), 14 ) dmp from (select 90100+level num from dual connect by level <= 15)) select num, dmp, (select max(decode(rownum,4,column_value)) || ',' || max(decode(rownum,3,column_value)) || ',' || max(decode(rownum,2,column_value)) || ',' || max(decode(rownum,1,column_value)) from TABLE( str2tbl( dmp ) ) ) rev from data / pause set pause off 测试结果: SQL> create or replace type str2tblType as table of varchar2(30) 2 / 类型已创建。 SQL> create or replace function str2tbl( p_str in varchar2, p_delim in varchar2 default ',' ) return str2tblType 2 PIPELINED 3 as 4 l_str long default p_str || p_delim; 5 l_n number; 6 begin 7 loop 8 l_n := instr( l_str, p_delim ); 9 exit when (nvl(l_n,0) = 0); 10 pipe row( ltrim(rtrim(substr(l_str,1,l_n-1))) ); 11 l_str := substr( l_str, l_n+1 ); 12 end loop; 13 return; 14 end; 15 / 函数已创建。 SQL> set echo on SQL> column dmp format a10 SQL> column rev format a10 SQL> with data as 2 (select num, substr( dump(num,16), 14 ) dmp 3 from (select 90100+level num from dual connect by level <= 15)) 4 select num, dmp, 5 (select max(decode(rownum,4,column_value)) || ',' || 6 max(decode(rownum,3,column_value)) || ',' || 7 max(decode(rownum,2,column_value)) || ',' || 8 max(decode(rownum,1,column_value)) 9 from TABLE( str2tbl( dmp ) ) ) rev 10 from data 11 / NUM DMP REV ---------- ---------- ---------- 90101 c3,a,2,2 2,2,a,c3 90102 c3,a,2,3 3,2,a,c3 90103 c3,a,2,4 4,2,a,c3 90104 c3,a,2,5 5,2,a,c3 90105 c3,a,2,6 6,2,a,c3 90106 c3,a,2,7 7,2,a,c3 90107 c3,a,2,8 8,2,a,c3 90108 c3,a,2,9 9,2,a,c3 90109 c3,a,2,a a,2,a,c3 90110 c3,a,2,b b,2,a,c3 90111 c3,a,2,c c,2,a,c3 NUM DMP REV ---------- ---------- ---------- 90112 c3,a,2,d d,2,a,c3 90113 c3,a,2,e e,2,a,c3 90114 c3,a,2,f f,2,a,c3 90115 c3,a,2,10 10,2,a,c3 已选择15行。 SQL> 域索引的测试 ~~~~~~~~~~~~~~ drop table t; create table t ( x varchar2(50) ); insert into t values ( '1 12345 987' ); insert into t values ( '1 12345 987 567' ); create index t_idx on t(x) indextype is ctxsys.context; select x, score(0) from t where contains( x, '1 or 12345 or 567', 0 ) > 0 order by 2 desc / 10g下测试:9i下报错 SQL> create table t ( x varchar2(50) ); 表已创建。 SQL> SQL> insert into t values ( '1 12345 987' ); 已创建 1 行。 SQL> insert into t values ( '1 12345 987 567' ); 已创建 1 行。 SQL> create index t_idx on t(x) indextype is ctxsys.context; 索引已创建。 SQL> select x, score(0) 2 from t 3 where contains( x, '1 or 12345 or 567', 0 ) > 0 4 order by 2 desc 5 / X SCORE(0) -------------------------------------------------- ---------- 1 12345 987 567 4 1 12345 987 3