索引组织表
索引组织表的存储结构是按照主键的 B-tree 结构搭建的。不象普通的表(堆 积表——数据的存储是无序进行的),索引组织表中的数据是按照主键的 B-tree 结构排序后保存的。包括保存索引组织表行的主键字段值在内,B-tree 中的每一 个索引项还保存了非键字段的值。
组织索引表实际上就是索引的表化
为什么要引进组织索引表
create table org_index_table
( object_id int primary key,
oname varchar2(30),
owner varchar2(30),
status varchar2(30))
organization index;
create table heap_table
( object_id int primary key,
oname varchar2(30),
owner varchar2(30),
status varchar2(30)
)
alter table org_index_table nologging;
alter table heap_table nologging;
create table s_table as
select object_id, object_name, owner,status
from all_objects
insert into heap_table select * from s_table
call count cpu elapsed disk query current rows
------- ------ -------- -------------------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 1 0 0
Execute 1 0.48 0.62 90 2301 11134 70231
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- -------------------- ---------- ---------- ----------
total 2 0.50 0.63 90 2302 11134 70231
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 114
Rows Row Source Operation
------- ---------------------------------------------------
0 LOAD TABLE CONVENTIONAL (cr=2575 pr=90 pw=90 time=0 us)
70231 TABLE ACCESS FULL S_TABLE (cr=450 pr=88pw=88 time=1380 us cost=128 size=4239300 card=81525)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
db file scattered read 16 0.08 0.14
db file sequential read 8 0.01 0.02
log file sync 1 0.00 0.00
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 0.00 0.00
Insert into org_index_table select* from s_table
call count cpu elapsed disk query current rows
------- ------ -------- -------------------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.39 0.57 0 2389 10939 70231
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- -------------------- ---------- ---------- ----------
total 2 0.39 0.57 0 2390 10939 70231
Rows Row Source Operation
------- ---------------------------------------------------
0 LOAD TABLE CONVENTIONAL (cr=2535 pr=0 pw=0 time=0 us)
70231 TABLE ACCESS FULL S_TABLE (cr=450 pr=0 pw=0time=1079 us cost=128 size=4239300 card=81525)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
log buffer space 1 0.14 0.14
log file sync 1 0.02 0.02
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 0.00 0.00
selectindex_name,table_name
fromuser_indexes
wheretable_name in( 'HEAP_TABLE','ORG_INDEX_TABLE')
INDEX_NAME | TABLE_NAME |
SYS_C0016433 | HEAP_TABLE |
SYS_IOT_TOP_84235 | ORG_INDEX_TABLE |
begin
scott.show_space(p_segname =>'HEAP_TABLE');
end;
Unformatted Blocks .....................0
FS1 Blocks (0-25) ......................0
FS2 Blocks (25-50) .....................0
FS3 Blocks (50-75) .....................1
FS4 Blocks (75-100).....................52
Full Blocks ............................443
Total Blocks............................512
Total Bytes.............................4194304
Total MBytes............................4
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................4
Last Used Ext BlockId...................441609
Last Used Block.........................128
select * from user_tables where table_name in( 'HEAP_TABLE','ORG_INDEX_TABLE')
我们看不到块的个数
begin
scott.show_space(p_segname =>'ORG_INDEX_TABLE');
end;
出现错误
怎么看着个表的大小?
select * from user_segments where segment_name='ORG_INDEX_TABLE'
也看不到数据
analyze index SYS_IOT_TOP_84235 validate structure
HEIGHT | 2 |
BLOCKS | 512 |
NAME | SYS_IOT_TOP_84235 |
PARTITION_NAME | |
LF_ROWS | 70231 |
LF_BLKS | 440 |
LF_ROWS_LEN | 3350295 |
LF_BLK_LEN | 8000 |
BR_ROWS | 439 |
BR_BLKS | 1 |
BR_ROWS_LEN | 4757 |
BR_BLK_LEN | 8032 |
DEL_LF_ROWS | 0 |
DEL_LF_ROWS_LEN | 0 |
DISTINCT_KEYS | 70231 |
MOST_REPEATED_KEY | 1 |
BTREE_SPACE | 3528032 |
USED_SPACE | 3355052 |
PCT_USED | 96 |
ROWS_PER_KEY | 1 |
BLKS_GETS_PER_ACCESS | 3 |
PRE_ROWS | 0 |
PRE_ROWS_LEN | 0 |
OPT_CMPR_COUNT | 0 |
OPT_CMPR_PCTSAVE | 0 |
analyze index SYS_C0016433 validate structure
HEIGHT | 2 |
BLOCKS | 256 |
NAME | SYS_C0016433 |
PARTITION_NAME | |
LF_ROWS | 70231 |
LF_BLKS | 243 |
LF_ROWS_LEN | 1043578 |
LF_BLK_LEN | 8000 |
BR_ROWS | 242 |
BR_BLKS | 1 |
BR_ROWS_LEN | 2612 |
BR_BLK_LEN | 8032 |
DEL_LF_ROWS | 0 |
DEL_LF_ROWS_LEN | 0 |
DISTINCT_KEYS | 70231 |
MOST_REPEATED_KEY | 1 |
BTREE_SPACE | 1952032 |
USED_SPACE | 1046190 |
PCT_USED | 54 |
ROWS_PER_KEY | 1 |
BLKS_GETS_PER_ACCESS | 3 |
PRE_ROWS | 0 |
PRE_ROWS_LEN | 0 |
OPT_CMPR_COUNT | 0 |
OPT_CMPR_PCTSAVE | 0 |
我们看看执行计划
explain plan for
select * from ORG_INDEX_TABLE t
where t.object_id=30
select * from table(dbms_xplan.display())
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 46 | 1 (0)| 00:00:01 |
|* 1 | INDEX UNIQUE SCAN|SYS_IOT_TOP_84235 | 1 | 46 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
我们并没有看到TABLE ACCESS BY INDEX ROWID,说明其他字段信息存放在SYS_IOT_TOP_84235
下面一个执行计划继续说明我们的结论
explain plan for
select * from ORG_INDEX_TABLE t
where t.oname='xxxx'
select * from table(dbms_xplan.display())
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 702 | 32292 | 122 (1)| 00:00:02 |
|* 1 | INDEX FASTFULL SCAN| SYS_IOT_TOP_84235 | 702 | 32292 | 122 (1)| 00:00:02 |
------------------------------------------------------------------------------------------
)
我们查找的字段并不是主键,然而还是走索引了,只是走的是全索引扫描。
explain plan for
select * from HEAP_TABLE t
where t.object_id=30
select * from table(dbms_xplan.display())
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 44 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID|HEAP_TABLE | 1 | 44 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | SYS_C0016433 | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
对比而言,我们看到组织索引表在查找某些数据(根据主键),没有出现TABLE ACCESS BY INDEX ROWID, 因此提高了查询效率。
从以上分析可以看出,索引组织表有些象普通表与单独索引组成的配置,只不过 没有维护两个单独的存储结构,数据库仅维护一个单独的 B-tree 索引。因此, 每一个索引项包含了<primary_key_value,non_primary_key_column_values>。
使用索引组织表的好处。
索引组织表通过主键或可以成为主键合法前缀的任何键提供了对表数据的 更快访问,在 B-tree 叶块中出现的非键字段避免了额外的数据块访问。同时, 由于数据行是按照主键的顺序进行存储的,对主键或合法前缀的范围扫描只涉及 到最小数据块的访问。
我们看到组织索引表示一个全新类型的表,在查询时候,我们发现由于没有TABLE ACCESS BY INDEX ROWID ,从而提高了查询的性能。oracle数据库不会提供一个全方面全天候的优化技术。了解组织索引表以及适合应用场所,就显得很有必要。
组织索引表的基本存储
我们删除一部分数据,然后再插入这部分数据,观察数据存储
HEIGHT | 2 | 2 | 2 |
BLOCKS | 512 | 512 | 512 |
NAME | SYS_IOT_TOP_71372 | SYS_IOT_TOP_71372 | SYS_IOT_TOP_71372 |
PARTITION_NAME | |||
LF_ROWS | 68261 | 68261 | 68261 |
LF_BLKS | 417 | 417 | 417 |
LF_ROWS_LEN | 3271826 | 3271826 | 3271826 |
LF_BLK_LEN | 8000 | 8000 | 8000 |
BR_ROWS | 416 | 416 | 416 |
BR_BLKS | 1 | 1 | 1 |
BR_ROWS_LEN | 4517 | 4517 | 4517 |
BR_BLK_LEN | 8032 | 8032 | 8032 |
DEL_LF_ROWS | 0 | 34110 | 0 |
DEL_LF_ROWS_LEN | 0 | 1643446 | 0 |
DISTINCT_KEYS | 68261 | 68261 | 68261 |
MOST_REPEATED_KEY | 1 | 1 | 1 |
BTREE_SPACE | 3344032 | 3344032 | 3344032 |
USED_SPACE | 3276343 | 3276343 | 3276343 |
PCT_USED | 98 | 98 | 98 |
ROWS_PER_KEY | 1 | 1 | 1 |
BLKS_GETS_PER_ACCESS | 3 | 3 | 3 |
PRE_ROWS | 0 | 0 | 0 |
PRE_ROWS_LEN | 0 | 0 | 0 |
OPT_CMPR_COUNT | 0 | 0 | 0 |
OPT_CMPR_PCTSAVE | 0 | 0 | 0 |
1、我们隔行删除一半数据记录
delete from ORG_INDEX_TABLE where mod(object_id,2) = 1;
analyze index SYS_IOT_TOP_84235 validate structure;
select * fromindex_stats
alter table ORG_INDEX_TABLE move online;
analyze index SYS_IOT_TOP_84235 validate structure;
select *from index_stats
HEIGHT | 2 | 2 | 2 |
BLOCKS | 512 | 512 | 256 |
NAME | SYS_IOT_T… | SYS_IOT… | SYS_IOT_... |
PARTITION_NAME | |||
LF_ROWS | 70231 | 70231 | 35124 |
LF_BLKS | 440 | 440 | 233 |
LF_ROWS_LEN | 3350295 | 3350295 | 1667079 |
LF_BLK_LEN | 8000 | 8000 | 8000 |
BR_ROWS | 439 | 439 | 232 |
BR_BLKS | 1 | 1 | 1 |
BR_ROWS_LEN | 4757 | 4757 | 2521 |
BR_BLK_LEN | 8032 | 8032 | 8032 |
DEL_LF_ROWS | 0 | 35107 | 0 |
DEL_LF_ROWS_LEN | 0 | 1683216 | 0 |
DISTINCT_KEYS | 70231 | 70231 | 35124 |
MOST_REPEATED_KEY | 1 | 1 | 1 |
BTREE_SPACE | 3528032 | 3528032 | 1872032 |
USED_SPACE | 3355052 | 3355052 | 1669600 |
PCT_USED | 96 | 96 | 90 |
ROWS_PER_KEY | 1 | 1 | 1 |
BLKS_GETS_PER_ACCESS | 3 | 3 | 3 |
PRE_ROWS | 0 | 0 | 0 |
PRE_ROWS_LEN | 0 | 0 | 0 |
OPT_CMPR_COUNT | 0 | 0 | 0 |
OPT_CMPR_PCTSAVE | 0 | 0 | 0 |
Shrink 与 rebuild又会怎样?
alter index SYS_IOT_TOP_84235 rebuild
ERROR at line 1:
ORA-28650: Primary index on an IOT cannot be rebuilt
我们看到不能通过move 二只能用 rebuild index来重新组织数据,从而减少空行,或者空数据块的目的。
组织索引表的ROWID
为了实现对最长访问字段的最快访问,可以使用 rowoverflow 存储选项(稍后会祥述 ),将不常被访问的字段从 B-tree 叶块中取出放到一个可选的 (heap-organized)存储区域,从而限制了真正保存在 B-tree 叶块中的数据行 的大小与内容,并可导致在较小的 B-tree 中保存更多的数据行。不象 heap-organized 配置的情况(表的主键在表和索引中都要保存),索引 组织表没有这种重复存储的情况发生,因为主键字段的值仅保存在 B-tree 索引 中。
由于数据行按照主键的顺序进行保存,通过键压缩特性可以节省出来的大量 空间。
基于逻辑 rowid 的主键的使用(与物理 rowid 相对应),在索引组织表中的 第二个索引还提供了高可用性。这是因为,rowid 的本身逻辑特性——即使在进行了引起基表数据行移动的表重做操作之后,第二索引也不会变得不可用。与此 同时,通过在逻辑 rowid 的物理推测的使用。
select object_id, rowidfrom ORG_INDEX_TABLE where object_id=281
281 *BAEAGSUDwgNS/g
delete from ORG_INDEX_TABLE where object_id=281
insert into ORG_INDEX_TABLE
select * from s_table whereobject_id=281
select object_id, rowid from ORG_INDEX_TABLE whereobject_id=281
281 *BAEAGSUDwgNS/g
看到插入数据后,rowid并没有发生变化。
组织索引表的rowid是逻辑rowid,在堆栈表(正常的heap table)中,rowid没有*, 我们不能根据组织索引表的rowid来推算当前数据所在的数据文件,块号,以及行
运行以下的sql,会引起以下错误信息:
ORA-01410: 无效的 ROWID
ORA-06512: 在 "SYS.DBMS_ROWID", line 114
ORA-06512: 在 line 1
我们已经知道组织索引表本质上就是一个索引,而索引是一个比表复杂的多的数据结构,维护索引产生比维护堆栈表产生更多的redo
truncate tableorg_index_table;
truncate table heap_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
22304700
insert intoorg_index_table
select * from s_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
33991716
select 33991716- 22304700 from dual
11687016
insert into heap_table
select * from s_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
43551060
select 43551060-33991716 fromdual;
9559344
观察到插入组织索引表产生的redo要比插入堆栈表并维护一个主键产生的redo还要多。
我们在察看直径路径加载是否对组织索引表有效
truncate tableorg_index_table;
truncate table heap_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
43666448
insert /*+append*/ intoorg_index_table
select * from s_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
55338096
select 55338096- 43666448 from dual
11671648
11687016(没有/*+append*/提示的普通加载)
insert /*+append*/ intoheap_table
select * from s_table;
select a.sid,a.statistic#,a.value
from v$sesstat a, v$statname b
where a.STATISTIC#=b.STATISTIC# and
b.NAME like 'redo size' and
sid=( select sid fromv$mystat where rownum=1)
59308224
select 59308224-55338096 fromdual;
3970128
9559344(没有/*+append*/提示的普通加载)
我们观察到,对组织索引表直径路径加载并没有减少redo的产生量。
我们对比插入组织索引表与堆栈表所产生的拴与锁的对比,还能看到插入组织索引表需要更多的资源。实际上对表进行DML操作都会引起更大的资源消耗。
这也说明了 组织索引表的一些使用场所。
Index-Organized Tableswith Row Overflow Area
B-tree 索引项通常是比较小,因为每一个索引项的组成仅是键值和 rowid。 但是,在索引组织表,B-tree 索引项可能会变得比较大,因为其中包含了整个数
应用程序操控索引组织表的方式与操控普通表相同——使用 SQL 命令。但
是,数据库系统的通过操控对应的 B-tree 索引来执行所有的操作。
下表显示了索引组织表与普通表的不同。
普通表 | 索引组织表 |
rowid 唯一地识别每一行,主键是可选的设定项目。 |
主键唯一地识别每一行,主键必须被设定。 |
ROWID 隐含字段中的物理 rowid 可以用于创建第二个索引 | ROWID 隐含字段中的逻辑 rowid 可以用于创建第二个索引 |
基于 rowid 进行数据访问 | 基于逻辑 rowid 进行数据访问 |
连续扫描返回所有的行 | 全索引扫描返回所有的行 |
可以与其他表一起保存在簇中 | 不能够保存在簇中 |
可以包含数据类型位 LONG 和 LOB 的字段 | 可以包含数据类型位 LOB 的字段,但是不 能包含数据类型位 LONG 的字段 |
组合索引表还有3个重要的参数
select dbms_metadata.get_ddl('TABLE','ORG_INDEX_TABLE') from dual
CREATE TABLE"TIWEN"."ORG_INDEX_TABLE"
( "OBJECT_ID"NUMBER(38,0),
"ONAME" VARCHAR2(30),
"OWNER" VARCHAR2(30),
"STATUS" VARCHAR2(30),
PRIMARY KEY ("OBJECT_ID") ENABLE
) ORGANIZATION INDEX NOCOMPRESSPCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELISTGROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
PCTTHRESHOLD 50
主键总是要存在索引叶结点块上
在一个8k的数据块上,PCTTHRESHOLD 50表示,如果一行数据如果字节数>4k 则这个行的一部分数据存在另一个非索引块上(溢出块),至于哪一些数据存储在块上,还要察看其它的一些参数。
Including 行中的第一列到including指定的列存放在索引块上,剩余部分存放在溢出块。
CREATE TABLE "TIWEN"."ORG_INDEX_TABLE"
( OBJECT_IDNUMBER(38,0),
ONAME VARCHAR2(30),
OWNER VARCHAR2(30),
STATUS VARCHAR2(30),
PRIMARY KEY ("OBJECT_ID") ENABLE
)
Organization index
Include ONAME overflow
这张表的object_id oname存放在索引块上,而剩余部分存放在溢出块上。
产看下面的3个语句的执行计划
select * from org_index_table_1
where object_id=312
select * from org_index_table_1
where oname='I_DIR$SERVICE_UI'
select owner from org_index_table_1
where owner='SYS'
我们并不能从执行计划产看,什么数据在索引块上,什么数据在溢出块上。
但是我们可以看到索引快以及溢出块所在的段
CREATE TABLE TIWEN.ORG_INDEX_TABLE_2
( OBJECT_IDNUMBER(38,0),
ONAME VARCHAR2(30),
OWNER VARCHAR2(30),
STATUS VARCHAR2(30),
PRIMARY KEY (OBJECT_ID) ENABLE
) ORGANIZATION INDEX NOCOMPRESSPCTFREE 10 INITRANS2 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS1 BUFFER_POOLDEFAULT)
TABLESPACE USERS
PCTTHRESHOLD 1 INCLUDINGONAME OVERFLOW
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS1 BUFFER_POOLDEFAULT)
TABLESPACE example
select replace(dbms_metadata.get_ddl('TABLE','ORG_INDEX_TABLE_1'),'"',null) fromdual
insert intoorg_index_table_2
select * from s_table
analyze tableorg_index_table_2 compute statistics
for table
for all indexes
for all indexed columns
select * fromorg_index_table_1
where object_id=312
select * fromorg_index_table_1
where oname='I_DIR$SERVICE_UI'
select owner from org_index_table_2
where owner='SYS'
select * from user_segments where segment_name='SYS_IOT_TOP_71389'
select * from dba_segments where owner='TIWEN' andtablespace_name='EXAMPLE'
select * from dba_segments where segment_name='SYS_IOT_TOP_71389'
select * from user_segments where segment_name
组织索引表上的在次索引
SQL>create bitmap index idx_bit_owner onorg_index_table_2(owner);
createbitmap index idx_bit_owner onorg_index_table_2(owner)
ORA-28669:在没有映射表的情况下, 不能在 IOT 上创建位图索引
ALTER TABLE org_index_table_2 MOVE MAPPING TABLE
之后就可以建立位图索引了
create index idx_bit_owner onorg_index_table_2(owner)
select count(*) from org_index_table_2 whereowner='SYS'
create table IOT_MAPPING_TEST (name varchar2(32),
nonumber,
constraint PK_IOT_MAPPING_TEST primary key(no)
)
organization index
mapping table;
Table created
SQL>
SQL> select table_name,iot_name,iot_type from user_tables wheretable_name='IOT_MAPPING_TEST';
TABLE_NAME IOT_NAME IOT_TYPE
------------------------------------------------------------ ------------
IOT_MAPPING_TEST IOT
select table_name,iot_name,iot_type from user_tables whereiot_type='IOT_MAPPING';
TABLE_NAME IOT_NAME IOT_TYPE
------------------------------------------------------------ ------------
SYS_IOT_MAP_56839 IOT_MAPPING_TEST IOT_MAPPING
alter table iot_mapping_test shrink space;
Table altered
SQL> alter table SYS_IOT_MAP_56839 shrink space;
alter table SYS_IOT_MAP_56839 shrink space
ORA-28668: cannot reference mapping table of an index-organized table
借助上面的测试,顺便介绍一下如何move IOT MAPPING TABLES。移动IOT MAPPING TABLES的语法是:
ALTER TABLE <TABLE_NAME> MOVE MAPPING TABLE TABLESPACE<TBS_NAME>;
下面做个简单的测试
SQL> select segment_name,segment_type,tablespace_name fromuser_segments where segment_name like '%MAP%';
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME
------------------------- ------------------ ---------------------
SYS_IOT_MAP_56839 TABLE DATA_01
PK_IOT_MAPPING_TEST INDEX DATA_01
SQL> alter table iot_mapping_test move tablespace users;
Table altered
SQL> select segment_name,segment_type,tablespace_name fromuser_segments where segment_name like '%MAP%';
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME
------------------------------- ------------------ -----------------
SYS_IOT_MAP_56839 TABLE DATA_01
PK_IOT_MAPPING_TEST INDEX USERS
可以看到,常规的move操作只是表索引移了。SQL> alter table iot_mapping_test movemapping table tablespace users;
Table altered
SQL> select segment_name,segment_type,tablespace_name fromuser_segments where segment_name like '%MAP%';
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME
------------------------- ------------------ ---------------------
SYS_IOT_MAP_56839 TABLE USERS
PK_IOT_MAPPING_TEST INDEX USERS
SQL>
OK,到这里mapping table被成功的移动了
据行的内容。这个确定有时会破坏 B-tree 索引的 dense clustering property。
Oracle 针对以上问题,提出了 OVERFLOW 子句。如果必要,可以设定 OVERFLOW 表空间,每个数据行可以被分割为两部分,一部分用于存储索引项, 另一部分保存在 overflow 存储区域中,如下所示:
„ 索引项,其中包含了所有主键字段的字段值,还包含了指向 overflow 部 分的物理 rowid,以及可选的一些非键字段;
„ overflow 部分,包含了没有保存在索引项中的其他非键字段。
有了 OVERFLOW 子句,还可以使用另外两个子句,PCTTHRESHLOD 和 INCLUDING子句,控制 Oracle 如何分割每一个数据行。通过使用 PCTTHRESHOLD 子句,可以设定 block size 的百分比的阙值,如果所有的非键字段的值没有超出 这个阙值,则这个数据行将不被分割为两部分。否则,从第一个不能满足阙值的 非键字段开始,其余的非键字段将全部被保存到 overflow 存储区域中。
INCLUDING 子句可以让 DBA 设定任何需要被保存到 overflow 存储区域的
在已经设定的字段之后在 CREATE TABLE 命令中出现的非键字段的名称,需要注 意的是,由于 PCTTHRESHOLD 设定的限制,可能会有其他非键字段会保存在 overflow 中。
同时参看: Oracle9i Database Administrator’s Guide for examples of using the
OVERFLOW clause
1.1.3 SecondaryIndexes on Index-Organized Tables
在索引组织表中支持的第二索引提供了对既不使用主键字段也不使用主键 字段前缀的表的高效访问。可以选择的,逻辑 rowid 可以包含一个 physical guess
——用于识别每一数据行的 block 位置。Oracle 使用物理推测特性直接探明到索
引组织表的叶块中,并绕过主键搜索。由于在索引组织表中数据行没有永久的物 理地址,当行被移动到另一个新 block 中时,物理推测可以变得稳定。
对于常规表,通过第二索引的访问将引起第二索引的扫描和额外的 I/O,从
而获得包含数据行的数据块。对于索引组织表,依赖于物理推测的使用和正确与 否,通过第二索引访问是不同的:
„ 没有物理推测,访问将引起两个索引扫描:在发生主键索引扫描之后, 紧接着会发生第二索引的扫描;
„ 如果物理推测是正确的,访问将引起
„ 如果物理推测是错误的,访问则在主键索引扫描之后,发生第二索引的 扫描和额外的 I/O 操作获得包含数据行的数据块;
1.1.4 BitmapIndexes on Index-Organized Tables
Oracle 支持在索引组织表上使用位图索引。为了在索引组织表上创建位图 索引,需要一个 mapping table——映射表。
映射表是一个保存索引组织表逻辑 rowid 的堆积组织表。特别的,映射表的 每一个数据行保存了索引组织表中对应数据行的逻辑 rowid。因此,映射表提供 了索引组织表逻辑 rowid 与映射表数据行物理 rowid 之间的一一映射。
索引组织表中位图索引与常规表中的位图索引相类似,但是索引组织表中的 位图索引使用的 rowid 是映射表的 rowid。每一个索引组织表都有一个映射表, 而且作为索引组织表的位图索引的基表。
在索引组织表和常规表中,对位图索引的访问是通过 serach key 完成。如
果 key 被找到,位图项将被转换为物理 rowid。在常规表的情况中,物理 rowid 将被直接用于访问基表。但是,在索引组织表的情况中,物理 rowid 则被用于访 问映射表。The access to the mappingtable yields a logical rowid。逻辑 rowid 被用于访问索引组织表。
尽管索引组织表上的位图索引不保存逻辑 rowid,但是它仍然是一个逻辑上 的概念。
注意:索引组织表中的数据行移动并不 leave 在这个索引组织表上建立的位
图索引不可用。索引组织表中的数据行移动将使物理推测变为非法。但是,索引 组织表仍然可以通过主键访问。
1.1.5 PartitionedIndex-Organized Tables
可以通过在字段值 RANGE 或 HASH 执行对索引组织表的分区操作。分区 字段必须构成主键字段的子集。就像常规表,索引组织表同样支持本地分区(前
缀和非前缀)索引和全局分区(前缀)索引。
1.1.6 B-tree Indexes on UROWID Columns for Heap-and Index-Organized Tables
UROWID 数据类型字段可以保存逻辑主键。Oracle9i 常规表和索引组织表
的 UROWID 数据类型字段上支持索引。The index supports equality predicates on UROWID columns. For predicates other than equality or for ordering on
UROWID datatype columns,the index is not used。
1.1.7 Index-OrganizedTable Applications
较为出众的查询性能、高可用性特性、减少存储空间的需要等特性使索引组 织表特别适用于以下类型的应用:
„ Online Transaction Processing (OLTP)
„ Internet (for example,search engines and portals)
„ E-Commerce (for example,electronic stores and catalogs)
„ Data Warehousing
„ Time-series applications
原创文章,如果转载,请标注作者:田文 优快云地址:http://blog.youkuaiyun.com/tiwen818