索引組織表上建立BITMAP索引(二)

yangtingkun發表於2010-08-11

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章