oracle 點陣圖索引(bitmap index)

賀子_DBA時代發表於2018-01-18
今天研究下oracle中的點陣圖索引,透過這邊文章你會了解到,什麼是點陣圖索引?,什麼情況下應該使用點陣圖索引?點陣圖索引的檢索資料的過程,以及點陣圖索引的弊端?
一:什麼是點陣圖索引?
點陣圖索引是從oracle 7.3版本開始引入的。目前oracle企業版和個人版都支援點陣圖索引,但是標準版不支援。點陣圖索引是這樣一種結構,其中用一個索引鍵條目儲存指向多行的指標,這與B*樹結構不同,在b*樹結構中,索引鍵和表中的行存在著對應關係。在點陣圖索引中,可能只有很少的索引條目,每個索引條目指向多行,而在傳統的B*樹中,一個索引條目就指向一行那麼什麼是點陣圖索引呢?(借用網路的例子講解)
  有張表名為table的表,由三列組成,分別是姓名、性別和婚姻狀況,其中性別只有男和女兩項,婚姻狀況由已婚、未婚、離婚這三項,該表共有100w個記錄。現在有這樣的查詢:select * from table where Gender=‘男’ and Marital=“未婚”;

1)不使用索引
不使用索引時,資料庫只能一行行掃描所有記錄,然後判斷該記錄是否滿足查詢條件。
2)B樹索引
對於性別,可取值的範圍只有'男','女',並且男和女可能各站該表的50%的資料,這時新增B樹索引還是需要取出一半的資料, 因此完全沒有必要。相反,如果某個欄位的取值範圍很廣,幾乎沒有重複,比如身份證號,此時使用B樹索引較為合適。事實上,當取出的行資料佔用表中大部分(超過20%)的資料時,即使新增了B樹索引,資料庫如oracle、mysql也不會使用B樹索引,很有可能還是一行行全部掃描。
接下來說下點陣圖索引原理:
如果在性別列上建立了點陣圖索引,對於性別這個列,針對每行的rowid(rowid可以理解為每行的物理位置),點陣圖索引形成兩個向量,男向量為10100...,向量的每一位表示該行是否是男,如果是則位1,否為0,同理,女向量位01011,(可以理解為給每行資料的性別列中為產生兩個向量分別為男向量和女向量:男向量中 值為男:用1表示,值不是男用0表示,同理女向量中 值為女:用1表示,值不是女:用0表示)

如果在婚姻狀況列上建立了點陣圖索引 對於婚姻狀況這一列,點陣圖索引生成三個向量,已婚為11000...,未婚為00100...,離婚為00010...。

二:oracle 點陣圖索引檢索資料的過程:
當我們使用查詢語句“select * from table where Gender=‘男’ and Marital=“未婚”;”的時候 首先取出男向量10100...,然後取出未婚向量00100...,將兩個向量做and操作,這時生成新向量00100...,可以發現rowid=3的and之後的結果為1,表示該表的rowid=3的這行資料就是我們需要查詢的結果(如下“and的結果”為1的就是需要查詢的結果),然後根據rowid找到需要的資料

三:什麼情況下應該使用點陣圖索引?
點陣圖索引適合只有幾個固定值的列,如性別、婚姻狀況、行政區等等,而身份證號這種型別不適合用點陣圖索引,如果使用者查詢的列的相異基數非常的小, 要為這些相異基數值比較小的列建索引,就需要建立點陣圖索引。
那麼何謂相異基數非常的小?可以認為行集中不同項的個數除以行數應該是一個很小的數(接近0),例如,某個列(性別)可能取值為M、F、null.如果一個表中有20000條資料,那麼3/20000=0.00015,那麼這就算是個相異基數很小的情況,類似的,如果有100000個不同的值,與10000000條結果相比,比值是0.01,同樣也很小,也可以認為是相異基數很小的情況,都可以建立點陣圖索引;
四:點陣圖索引的限制或者說是弊端?
點陣圖索引在讀密集的環境中能很好地工作,但是對於寫密集的環境則極不適合,原因在於,一個點陣圖索引鍵條目(可以理解為前面的男 、女、未婚、已婚等)指向多行。如果一個會話修改了有索引的列的資料,那麼大多數情況下,這個索引條目只想的所有行都會被鎖定。oracle無法鎖定一個點陣圖索引條目中的單獨一位,而是會鎖定整個點陣圖索引條目,倘若其他會話修改也需要更新同樣的這個點陣圖索引條目,就會被“關在門外”,這樣就大大影響了併發性,因為每個更新都有可能鎖定數百行,不允許併發地更新他們的點陣圖列;
舉個例子說明:有這樣一個欄位job,記錄各個員工的職位如:dba 、java、php等等 ,假設我們在這個job列上建立了點陣圖索引。假如rowid=100的員工職業為php,rowid=120的員工職業為php;
如果會話1使用update更新某個員工的職位(job),比如update table set table.job='dba' where rowid=100;,但還沒有commit,而會話2也使用update更新另一個員工的職位,update table set table.job='dba' where rowid=120; 這個時候會話2怎麼也更新不了,需要等待會話1 commit。
原因:會話1更新rowid=100的這個員工的職位,假如這個員工原來是php,現在改成dba,那麼在commit之前,就會鎖定所有job=php和job=dba的所有行,所以當會話2嘗試更新job=dba只能等待鎖,只有commit之後才解鎖。這樣就大大影響了併發性;
總結:
點陣圖索引是為資料倉儲(也就是查詢環境設計的),點陣圖索引特別不適合OLTP系統,點陣圖索引不適合與dml頻繁的環境,點陣圖索引適用於DSS系統,點陣圖索引不適合頻繁修改的系統,弊端是嚴重影響
併發性,因為update索引列值的時候,會鎖定新值和舊值指向的所有資料行,所以使用點陣圖索引需慎重。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29654823/viewspace-2150299/,如需轉載,請註明出處,否則將追究法律責任。

相關文章