Oracle的索引组织表也支持BITMAP索引类型,不过需要映射表的支持。
描述一下映射表的结构的特点。
索引组织表上创建BITMAP索引(一):http://yangtingkun.itpub.net/post/468/503513
上一篇文章介绍了索引组织表的映射表,下面简单描述一下映射表的结构,以及为什么Oracle需要这个映射表。
SQL> DROP TABLE T_INDEX_ORG;
表已删除。
SQL> CREATE TABLE T_INDEX_ORG
2 (ID NUMBER PRIMARY KEY,
3 NAME VARCHAR2(30),
4 TYPE VARCHAR2(30))
5 ORGANIZATION INDEX
6 MAPPING TABLE;
表已创建。
SQL> CREATE BITMAP INDEX IND_B_INDEX_TYPE
2 ON T_INDEX_ORG (TYPE);
索引已创建。
SQL> SELECT TABLE_NAME, IOT_NAME, IOT_TYPE
2 FROM USER_TABLES
3 WHERE IOT_TYPE IS NOT NULL;
TABLE_NAME IOT_NAME IOT_TYPE
------------------------------ ------------------------------ ------------
SYS_IOT_MAP_32399 T_INDEX_ORG IOT_MAPPING
T_INDEX_ORG IOT
SQL> SELECT TABLE_NAME, INDEX_NAME, INDEX_TYPE
2 FROM USER_INDEXES
3 WHERE TABLE_NAME = 'T_INDEX_ORG';
TABLE_NAME INDEX_NAME INDEX_TYPE
------------------------------ ------------------------------ -------------
T_INDEX_ORG SYS_IOT_TOP_32399 IOT - TOP
T_INDEX_ORG IND_B_INDEX_TYPE BITMAP
现在已经建立好索引组织表、映射表和BITMAP索引,首先来看看映射表的结构:
SQL> DESC SYS_IOT_MAP_32399
名称 是否为空? 类型
----------------------------------------------------------------- -------- --------------
SYS_NC_01 ROWID
映射表的结构很简单,只有一个ROWID字段。
下面在表中插入一条记录:
SQL> INSERT INTO T_INDEX_ORG VALUES (1, 'T_INDEX_ORG', 'IOT');
已创建 1 行。
可以看到,映射表中自动包含了ROWID信息。
SQL> SELECT * FROM SYS_IOT_MAP_32399;
SYS_NC_01
--------------------------------------------------
*BAAAAAACwQL+
根据这个ROWID,就可以从索引组织表找到对应的记录:
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BAAAAAACwQL+';
ID NAME TYPE
---------- ------------------------------ ------------
1 T_INDEX_ORG IOT
但是仔细观察一下,就会发现映射表中的ROWID与从索引组织表中查询得到的ROWID并不相同:
SQL> SELECT ROWID FROM T_INDEX_ORG;
ROWID
-------------------------------------
*BAJAADQCwQL+
通过DUMP看看二者的差别:
SQL> COL D_ROWID FORMAT A50
SQL> SELECT ROWID, DUMP(ROWID, 16) D_ROWID
2 FROM T_INDEX_ORG;
ROWID D_ROWID
------------------------------- ------------------------------------------------
*BAJAADQCwQL+ Typ=208 Len=10: 2,4,2,40,0,34,2,c1,2,fe
SQL> COL SYS_NC_01 FORMAT A30
SQL> SELECT SYS_NC_01, DUMP(SYS_NC_01, 16) D_ROWID
2 FROM SYS_IOT_MAP_32399;
SYS_NC_01 D_ROWID
------------------------------ --------------------------------------------------
*BAAAAAACwQL+ Typ=208 Len=10: 2,4,0,0,0,0,2,c1,2,fe
原来索引组织表的ROWID包括物理猜信息,而映射表保存的ROWID,没有记录物理地址信息,而只包括了索引组织表的主键。
那么索引组织表就有一个有趣的特性,可以通过多个ROWID访问相同的一条记录:
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BAJAADQCwQL+';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1 T_INDEX_ORG IOT
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BAAAAAACwQL+';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1 T_INDEX_ORG IOT
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BABCDAACwQL+';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1 T_INDEX_ORG IOT
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BADDDDACwQL+';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1 T_INDEX_ORG IOT
换句话说,只要ROWID包含的主键信息是正确的,就可以访问到对应的记录,而与逻辑ROWID中的物理地址是否存在、是否准确无关。
可以看到,前面两个ROWID分别是索引组织表真实的ROWID,以及映射表中保存的ROWID,但是后面两个ROWID,完全是根据ROWID的规则仿写的,而且居然也可以得到记录。
扯远一点,这一点就是逻辑ROWID和物理ROWID的一个重要区别。一条记录只有一个物理ROWID,而一个物理ROWID是在数据库中唯一的,它表示唯一一个物理地址,它可能对应到一条记录,也可能不对应任何一条记录。
而根据上面的结果也可以看到,多个逻辑ROWID可以指向同一条记录,也就是说1条记录对应多个逻辑ROWID。
而一个逻辑ROWID也可以指向多条记录,看一个简单的例子:
SQL> CREATE TABLE T_INDEX_ORG1
2 (ID NUMBER PRIMARY KEY)
3 ORGANIZATION INDEX;
表已创建。
SQL> INSERT INTO T_INDEX_ORG1 VALUES (1);
已创建 1 行。
SQL> SELECT ROWID FROM T_INDEX_ORG1;
ROWID
-----------------------------------------
*BAJABSwCwQL+
SQL> ALTER TABLE T_INDEX_ORG1 MOVE MAPPING TABLE;
表已更改。
SQL> SELECT TABLE_NAME, IOT_NAME, IOT_TYPE
2 FROM USER_TABLES
3 WHERE IOT_TYPE IS NOT NULL;
TABLE_NAME IOT_NAME IOT_TYPE
------------------------------ ------------------------------ ------------
SYS_IOT_MAP_32399 T_INDEX_ORG IOT_MAPPING
SYS_IOT_MAP_32427 T_INDEX_ORG1 IOT_MAPPING
T_INDEX_ORG IOT
T_INDEX_ORG1 IOT
SQL> SELECT * FROM SYS_IOT_MAP_32427;
SYS_NC_01
------------------------------
*BAAAAAACwQL+
SQL> SELECT * FROM T_INDEX_ORG
2 WHERE ROWID = '*BAAAAAACwQL+';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1 T_INDEX_ORG IOT
SQL> SELECT * FROM T_INDEX_ORG1
2 WHERE ROWID = '*BAAAAAACwQL+';
ID
----------
1
同一个逻辑ROWID可以指向不同表中的不同记录,只要它们的主键信息是相同的。
于是可以看到一个十分有趣的SQL:
SQL> SELECT A.ROWID, B.ROWID
2 FROM T_INDEX_ORG A, T_INDEX_ORG1 B
3 WHERE A.ROWID = B.ROWID;
ROWID ROWID
----------------------------------------- ------------------------------------
*BAJAADQCwQL+ *BAJABUwCwQL+
两个ROWID明明不等,但是居然可以查询出结果。这就是逻辑ROWID特点所造成的。
这次扯的真是有点远了,还是回到最初的话题。
可以看到,对于建立了映射表的索引组织表,在做任何修改的时候,都会同步修改映射表中的ROWID信息。而如果是通过ALTER TABLE MOVE MAPPING TABLE添加的映射表,会自动将目前索引组织表中所有记录的ROWID,添加到映射表中。
SQL> SELECT * FROM T_INDEX_ORG;
ID NAME TYPE
---------- ------------------------------ --------------------
1 T_INDEX_ORG IOT
SQL> SELECT * FROM SYS_IOT_MAP_32399;
SYS_NC_01
------------------------------
*BAAAAAACwQL+
SQL> UPDATE T_INDEX_ORG SET ID = 2;
已更新 1 行。
SQL> SELECT * FROM SYS_IOT_MAP_32399;
SYS_NC_01
------------------------------
*BAJAADQCwQP+
当记录的主键发生变化的时候,Oracle也会更新映射表中保存的逻辑ROWID信息。
在Oracle确保映射表和索引组织表的同步的情况下,就可以利用映射表来创建BITMAP索引了。
Oracle之所以无法直接在索引组织表上建立BITMAP索引,是因为BITMAP索引保存的是一个个ROWID范围,在这些范围内通过BITMAP来对应表的ROWID信息。而索引组织表的实际存储格式是索引,而索引的根节点、分支节点和叶节点都保存在一起,因此实际保存表数据的叶节点在一个EXTENT中是不连续的。
建立了映射表后,BITMAP索引实际是建立在映射表这个堆表上,通过映射表中保存的逻辑ROWID信息,对应到索引组织表中。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-670807/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-670807/