您好,登錄后才能下訂單哦!
位圖索引是oracle數據庫里除B樹索引之外的另外一種索引的類型,它主要用于數據倉庫或者DSS系統。在數據倉庫或DSS系統中,針對某些類型的sql,用位圖索引比用B樹索引要快很多,這主要是位圖索引實現了快捷的按位運算的緣故。
位圖索引的物理存儲結構和普通B樹索引的物理存儲結構相似,也是按照被索引的鍵值列有序存儲,只不過和索引鍵值一起存儲的不再僅僅是索引鍵值所對應的rowid,而是變成了三部分的組合。這三部分分別為對應rowid的下限,對應rowid的上限和被壓縮存儲的位圖(Bitmap Segment,位圖段最大只能為位圖索引葉子塊大小的1/2),即oracle數據庫中位圖索引的物理存儲結構:<被索引的鍵值,對應rowid的下限,對應rowid的上限,位圖段>,這里位圖段是壓縮存儲的,解壓縮后就是一連串0和1的二進制位圖序列,其中1表示被索引鍵值的一個有效rowid,oracle通過一個轉換函數(mapping function)將解壓縮段的位圖段中的1結合對應rowid的上下限,轉換為被索引鍵值所對應的有效rowid。
上述位圖索引的物理存儲結構決定了oracle數據庫中位圖索引的鎖粒度是在索引行的位圖段上。對于oracle數據庫的位圖索引而言,它是沒有行鎖這個概念的,要鎖就鎖索引行的整個位圖,而多個數據行可能對應同一索引的位圖段。這種鎖的粒度就決定了位圖索引不適用于高并發頻繁修改的OLTP系統,如果在高并發且頻繁修改的OLTP系統中使用了位圖索引,很可能會導致嚴重的并發問題,甚至會產生死鎖。
我們來看一個因為位圖索引而導致常見的并發insert操作出現死鎖的例子。創建一個測試表T1:
SQL> create table t1(id number,sex char(20));
Table created.
在T1表中插入10000條數據:
SQL> begin
2 for i in 1..5000 loop
3 insert into t1 values(i,'MALE');
4 insert into t1 values(i,'FEMALE');
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
在T1的列SEX上創建一個位圖索引IDX_BITMAP_T1:
SQL> create bitmap index idx_bitmap_t1 on t1(sex);
Index created.
現在我們來構造死鎖的情景,首先session 1中插入一條記錄但不commit:
SQL> insert into t1 values(10001,'MALE');
1 row created.
接著到session 2,插入一條記錄但不commit:
SQL> insert into t1 values(10002,'FEMALE');
1 row created.
回到session 1,再插入一條記錄,這時這個插入操作hang住了:
SQL> insert into t1 values(10003,'FEMALE');--hang住
再回到session 2,又插入一條記錄,這時這個插入操作也hang住了:
SQL> insert into t1 values(10004,'MALE');
第2次回到session 1,這里oracle已經檢測出了死鎖:
SQL> insert into t1 values(10003,'FEMALE');
insert into t1 values(10003,'FEMALE') *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
這里的原理是當插入一條記錄時,oracle需要去維護位圖索引IDX_BITMAP_T1中所對應鍵值的位圖段,因為記錄數較少并且oracle是壓縮存儲位圖段的緣故,所有sex值male的5000條記錄對應的都是同一條索引行,sex值為female的5000條記錄對應也是同一條索引行。這也意味著當插入一條新的sex值為male的那5000條記錄);但插入一條新的sex值為female的記錄時,oracle會鎖原先所有sex值為female的那5000條記錄所對應的位圖段(即相當于鎖了所有sex值為female的那5000條記錄),所以通常情況下不會出現死鎖的并發insert操作就這樣出現了死鎖。
與B樹索引相比,位圖索引的優勢主要體現在如下幾個方面:
(1)因為位圖索引的位圖段的是壓縮后存儲的,所以如果被索引的distinct值較少,那么位圖索引段與同列上的B樹索引比起來,會顯著節省空間。比如上例中表T的SEX列,其distinct 值僅為2,雖然表T1的數據量為10000,但SEX列上單鍵值位圖索引idx_bitmap_t中只有兩個索引行,而如果sex列上創建單鍵值B樹索引,則顯然該B樹索引中的索引行的數量會是10000.
(2)如果需要再多個列上創建索引,那么位圖索引與同等條件下的B樹索引比起來,往往會顯著節省存儲空間。比如針對表CUSTOMER上的三列master_status,region和gender,用戶可能會使用上述三列中任意單列或多列去訪問表customer,如果此時要建B樹索引,那么需要建三個復合B樹索引(這里考慮到了復合B樹索引可以代替單鍵值B樹索引嗎,三列復合B樹索引可以代替兩列復合B樹索引)才能涵蓋所有的情況,而如果是建位圖索引的話,則只需要建三個針對上述三列的單鍵值位圖索引就夠了。
(3)位圖索引能夠快速處理一些包含了各種AND或OR查詢條件的sql,這主要是因為位圖索引能夠實現快捷的按位運算的緣故。
關于位圖索引能夠實現快捷的按位運算的原理,我們用一個實例來說明。創建一個測試表customer:
SQL> create table customer(customer# number,marital_status varchar2(10),region varchar2(10),gender varchar2(10),income_level varchar2(10));
Table created.
使用如下sql插入6條記錄:
SQL> insert into customer values(101,'single','east','male','bracket_1');
1 row created.
SQL> insert into customer values(102,'married','central','female','bracket_4');
1 row created.
SQL> insert into customer values(103,'married','west','female','bracket_2');
1 row created.
SQL> insert into customer values(104,'divorced','west','male','bracket_4');
1 row created.
SQL> insert into customer values(105,'single','central','female','bracket_2');
1 row created.
SQL> insert into customer values(106,'married','central','female','bracket_3');
1 row created.
SQL> commit;
Commit complete.
在列region上創建一個位圖索引idx_b_region
SQL> create bitmap index idx_b_region on customer(region);
Index created.
在列martial_status上創建另外一個位圖索引idx_b_martialstatus:
SQL> create bitmap index idx_b_maritalstatus on customer(marital_status);
Index created.
SQL> select * from customer;
CUSTOMER# MARITAL_ST REGION GENDER INCOME_LEV
---------- ---------- ---------- ---------- ----------
101 single east male bracket_1
102 married central female bracket_4
103 married west female bracket_2
104 divorced west male bracket_4
105 single central female bracket_2
106 married central female bracket_3
6 rows selected.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。