位圖索引對數據表的列的每壹個鍵值分別存儲為壹個位圖,Oracle對於不同的版本,不同的操作方式,數據生成均有差別.
對於8i,9i,
下面分3種方式來討論數據的插入:
a.壹次插入壹行,插入多行後,壹次提交;
b.每插入壹行,提交壹次;
c.批量插入方式,壹次提交;
對於第壹種方式,觀察位圖索引的變化情況.
a.假設插入8行相同鍵值的數據,如果以每行方式插入,然後壹次提交,則會生成8個位圖
SQL> Insert Into H病人掛號記錄(Id,No,號別,執行人) Values(1,'G000001',1,'張1');
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> /
1 row inserted
SQL> commit;
Commit complete
SQL> alter system dump datafile 1 block 40028;
System altered
row#0[7847] flag: -----, lock: 0
col 0; len 3; (3): d5 c5 31 --鍵值'張1'
col 1; len 6; (6): 00 40 9c 54 00 00 --rowid的起始位置
col 2; len 6; (6): 00 40 9c 54 00 07 --rowid的終止位置
col 3; len 2; (2): c8 ff --位圖編碼
row#1[7802] flag: -----, lock: 0
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 2; (2): c8 03
row#2[7780] flag: -----, lock: 0
col 0; len 3; (3): d5 c5 32
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 1; (1): 02
row#3[7758] flag: -----, lock: 0
col 0; len 3; (3): d5 c5 33
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 1; (1): 03
row#4[7736] flag: -----, lock: 2
col 0; len 3; (3): d5 c5 34
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 1; (1): 04
row#5[7714] flag: -----, lock: 2
col 0; len 3; (3): d5 c5 35
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 1; (1): 05
----- end of leaf block dump -----
但是,下次再插入壹行相同鍵值的數據時,會自動合並這8行位圖為壹行位圖,並生成壹個新的索引位圖行存放剛插入行的索引:
SQL> Insert Into H病人掛號記錄(Id,No,號別,執行人) Values(1,'G000001',1,'張1');
1 row inserted
SQL> commit;
Commit complete
SQL> alter system dump datafile 1 block 40028;
System altered
row#0[7847] flag: -----, lock: 2
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 40 9c 54 00 00
col 2; len 6; (6): 00 40 9c 54 00 07
col 3; len 2; (2): c8 ff
row#1[7825] flag: -----, lock: 2
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 40 9c 54 00 08
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 1; (1): 00
----- end of leaf block dump -----
b.數據每行提交方式,與上面的情況相似,但有壹點不壹樣,每提交壹行,拷貝原來的位圖,生成新的位圖,並標記原來的位圖為已刪除,
標記為已刪除的位圖,只有索引塊需要分配新的位圖時,才會清除標記為已刪除的位圖,重用這些空間.
在8i,9i上實驗的結果,與ITPUB的<Oracle 數據庫性能優化>壹書378頁壹致.
如果1000條相同鍵值的數據插入,將生成125個包括8條記錄的位圖行.
c.第三種方式,批量插入數據,insert into H病人掛號記錄(Id,No,號別,執行人) select ***方式,
同壹鍵值,只生成壹次位圖,只有壹個位圖.
SQL> Insert Into H病人掛號記錄(Id,No,號別,執行人)
Select 1,'G000001',1,'張1' From dual
Union All
Select 2,'G000002',1,'張1' From dual
Union All
Select 3,'G000003',1,'張1' From dual
Union All
Select 4,'G000004',1,'張1' From dual
Union All
Select 5,'G000005',1,'張1' From dual
Union All
Select 6,'G000006',1,'張1' From dual
Union All
Select 7,'G000006',1,'張1' From dual
Union All
Select 8,'G000006',1,'張1' From dual
Union All
Select 9,'G000006',1,'張1' From dual;
SQL> commit;
Commit complete
SQL> alter system dump datafile 1 block 40028;
System altered
row#0[8006] flag: -----, lock: 2
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 40 9c 54 00 00
col 2; len 6; (6): 00 40 9c 54 00 0f
col 3; len 3; (3): c9 ff 01
row#1[8030] flag: ---D-, lock: 2
col 0; NULL
col 1; NULL
col 2; NULL
col 3; NULL
----- end of leaf block dump -----
所以,位圖索引最好采用批量插入方式,這樣,每個鍵值只生成壹個位圖.而單行數據插入方式,每個鍵值將每8行數據生成壹個位圖.
10G的情況,則簡單得多.
上面3種方式,相同鍵值的插入,位圖的生成是壹樣的,只有壹個位圖,並且,每次提交時,並不會刪除以前的位圖,而是直接修改對應鍵值的位圖.
每次插入壹行數據,插入9行後提交
row#0[7763] flag: ------, lock: 2, len=29
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 00 00 00 00 00
col 2; len 6; (6): 00 40 ef f2 00 0f
col 3; len 8; (8): f9 e4 d5 dc bc 01 ff 01
----- end of leaf block dump -----
再批量插入9行數據並提交
row#0[7733] flag: ------, lock: 2, len=30
col 0; len 3; (3): d5 c5 31
col 1; len 6; (6): 00 00 00 00 00 00
col 2; len 6; (6): 00 40 ef f2 00 17
col 3; len 9; (9): fa e4 d5 dc bc 01 ff ff 03
----- end of leaf block dump -----
可以看出,10G對位圖索引的存儲進行了優化,壹個鍵值在索引塊中只有壹個位圖
註意,其中有些結論並不是完全正確的,可以自己實驗證明,另外,該文涉及的實驗沒有標明Oracle版本,不同的版本,結果有差異.