點陣圖索引(Bitmap Index)——從B*樹索引到點陣圖索引
索引是我們最常使用的一種效能最佳化手段。本質上講,使用索引的優勢就是透過付出一個額外的索引塊掃描過程,獲取到符合條件的rowid集合,之後依據rowid集合訪問資料表塊。從而節省下進行全表搜尋的I/O消耗。
在各型別索引中,我們已經習慣使用的就是B*樹索引,也就是將索引列的取值構建為一顆平衡二叉樹。索引列每個非空行對應一個葉子節點,葉子節點上的內容包括索引取值和對應的rowid。B*樹的特點就是從根節點搜尋到葉子節點,所經過的路徑和消耗相同。
我們說B*樹索引是目前資料庫解決方案中普適性最好的一種索引型別。首先,B*索引適應各種型別資料庫,可以支援目前海量資料庫的大多數資料訪問需求。其次,對一般選擇性好的資料列,B*索引通常可以提供比較優秀的索引樹訪問執行計劃。最後,以Index Range Scan、Index Unique Scan、Index Fast Scan和Index Skip Scan為主體的Index執行計劃已經比較成熟,Oracle在處理此類問題上有很多獨有的技術可以使用。
但是,隨著資料分佈和取值的一些特殊性,在一些場合下,B*樹索引存在一些力不從心的現象。
ü 低基數資料列索引結構空間冗餘。B*樹結構中,索引列值和rowid都會儲存在索引的葉子節點上。如果索引列的選擇性差,只有少數的幾個可選取值,那麼在索引葉子節點上就是存在大量相鄰相同鍵值的葉子節點。這樣是一種嚴重的空間浪費和IO掃描浪費;
ü 單一索引路徑選擇。在通常的SQL條件中,常常包括多個條件列,這些條件列可能分別屬於不同的多個索引。但是由於B*樹索引的特殊性,我們的執行計劃中只能出現一個索引的執行路徑,其他列條件只能作為一種篩選條件出現。這樣,很多付出維護成本的索引就失去了意義;
ü 對Null值和OR條件的限制。傳統的B*樹索引,Null值是不會進入到索引結構的。同時對OR條件也存在很大的限制;
諸如此類,在一些情況下,B*樹索引是存在限制的。而這些問題,可以考慮透過點陣圖索引(Bitmap Index)來解決。
首先,點陣圖索引也是一種和資料表分開儲存的段segment結構,也是透過儘可能少讀塊block獲取結果集合rowid來實現最佳化目的的物件。點陣圖索引和B*樹索引的相同點,在於都是將平衡樹作為初始的結構。區別在於B*樹索引的葉子節點對應的是每一個索引列
ü Bitmap Index與傳統的B*樹結構最大的區別就是葉子節點的結構。對Bitmap Index來說,一個出現的索引列取值就對應著一個葉子節點。而B*樹是一個資料行對應一個葉子節點。這樣,也就意味著當索引列取值是低基數的時候,Bitmap Index結構要遠遠小於B*樹索引結構;
ü 第二部分的rowid範圍是用於進行偏移計算使用的。這部分記錄索引列對應的資料行起始和結束的rowid取值範圍;
ü 最後也是Bitmap的重中之重,就是點陣圖向量。在Bitmap Index中,使用計算機最小的計數單位:位bit來表示行取值情況。每一個資料行對應一位bit 0/1取值,如果資料表有1000行,那麼對應的向量就有1000位長度。針對某一位來說,如果對應行的取值和該向量所在葉子節點上對應索引取值相同,取值為1,否則為0;
ü
那麼,我們已經可以初步考慮到Oracle裡bitmap Index的基本結構。一顆葉子節點很少的樹(當列基數較小的時候,也就是列取值較小的時候),每個葉子節點對應一種可能的列取值。每個葉子節點上攜帶一個點陣圖向量,表示所有行對應取值的資訊。
下面,我們透過幾個簡單實驗,看看Bitmap Index的建立和使用情況。
首先是環境準備:
//在Oracle 11gR2上進行試驗;
SQL> select * from v$version where rownum<2;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
SQL> create table t as select object_id, owner, owner owner2 from dba_objects;
Table created
SQL> create index idx_t_owner on t(owner);
Index created
SQL> create bitmap index idx_t_ownerbit on t(owner2);
Index created
SQL> select count(distinct owner) from t;
COUNT(DISTINCTOWNER)
--------------------
30
SQL> select count(*) from t;
COUNT(*)
----------
72544
//構建一些空值
SQL> update t set wner=null, owner2=null where wner='ORDDATA';
248 rows updated
SQL> commit;
Commit complete
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
儲存結構上比較
在儲存結構上,資料表T包括超過7萬行記錄。對應的owner和owner2列取值完全一樣,差異在於構建的索引結構上。我們檢查一下兩個索引段(Index Segment)的情況。
SQL> col segment_name for a15;
SQL> select segment_name, segment_type, bytes, extents, blocks from dba_segments where wner='SYS' and segment_name like 'IDX_T%';
SEGMENT_NAME SEGMENT_TYPE BYTES EXTENTS BLOCKS
--------------- ------------------ ---------- ---------- ----------
IDX_T_OWNER INDEX 2097152 17 256
IDX_T_OWNERBIT INDEX 65536 1 8
資料表相同、取值相同,不同索引型別的儲存差異顯而易見。普通索引使用空間大小超過2M,共使用17個分割槽extents,摺合256個block。而Bitmap Index所消耗的空間還沒有超過初始物件分配的8個塊block大小。所以,在適當的索引值下,Bitmap Index儲存空間效率上有明顯優勢。
究其原因,也比較好理解。普通索引結構中,資料表增加一行,意味著要增加一個葉子節點。如果要超過原有的塊容量,還要進行分支節點、葉子節點的拆分問題。而Bitmap Index只需要在所有的葉節點點陣圖向量中增加一個bit位而已。
開篇我們提到過,索引的意義價值在於讀儘可能少的資料塊,獲取到rowid列表後到資料表中定位。在獲取資料集合相同的情況下,索引結構越小,帶來的IO損耗就越少,進而成本就越低。這種特性對於資料海量的OLAP、Dataware系統來說,至關重要!
普通索引列條件
對索引搜尋,Bitmap Index具有更高的執行成本優勢。
//普通索引結構
SQL> select * from t where wner='SCOTT';
已選擇36行。
已用時間: 00: 00: 00.01
執行計劃
----------------------------------------------------------
Plan hash value: 1516787156
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 103 | 1751 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 103 | 1751 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_T_OWNER | 103 | | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
17 consistent gets
11 physical reads
0 redo size
1013 bytes sent via SQL*Net to client
398 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
36 rows processed
//Bitmap Index搜尋路徑
SQL> select * from t where owner2='SCOTT';
已選擇36行。
已用時間: 00: 00: 00.01
執行計劃
----------------------------------------------------------
Plan hash value: 2207144928
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 103 | 1751 | 21 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | T | 103 | 1751 | 21 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS| | | | | |
|* 3 | BITMAP INDEX SINGLE VALUE | IDX_T_OWNERBIT | | | | |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OWNER2"='SCOTT')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
14 consistent gets
2 physical reads
0 redo size
1013 bytes sent via SQL*Net to client
398 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
36 rows processed
對比關係上,雖然兩者實際執行時間接近,但是使用Bitmap Index的執行計劃在IO處理量上具有比較明顯的優勢。
空值Null檢索性
在準備資料環境時,我們已經有意的構建一部分null進入owner/owner2資料列。下面我們來看看實際的效果。
//普通索引列
SQL> explain plan for select * from t where owner is null;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 248 | 4216 | 60 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 248 | 4216 | 60 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER" IS NULL)
13 rows selected
//Bitmap Index索引列
SQL> explain plan for select * from t where owner2 is null;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2207144928
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 248 | 4216 | 32
| 1 | TABLE ACCESS BY INDEX ROWID | T | 248 | 4216 | 32
| 2 | BITMAP CONVERSION TO ROWIDS| | | |
|* 3 | BITMAP INDEX SINGLE VALUE | IDX_T_OWNERBIT | | |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OWNER2" IS NULL)
15 rows selected
可以看出,對Null來說,是不會進入普通的B*樹,所以執行is null也就不可能出現索引路徑。而null作為一個可選取值列值,是可以作為一個葉子節點出現在Bitmap Index上的。
結論:B*樹索引在普適性上的優勢,可以滿足絕大多數的實際需求。但是一些特殊場景下,我們可以使用Bitmap索引來解決問題,提高資料表,特別是OLAP海量資料表的檢索效率問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-694870/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 點陣圖索引(轉載)索引
- Python點陣圖索引學習Python索引
- 點陣圖索引的工作原理 - Richard索引
- Android Bitmap(點陣圖)詳解Android
- 點陣圖(bitmap)原理以及實現
- oracle點陣圖索引對DML操作的影響Oracle索引
- 點陣圖
- MySQL點陣圖索引解決使用者畫像問題MySql索引
- 【技術總結】從Hash索引到LSM樹索引
- 跳槽必看MySQL索引:B+樹原理揭秘與索引優缺點分析MySql索引
- Redis 基礎 -- 點陣圖(bitmap)資料結構和 bitmap的常用命令Redis資料結構
- ClickHouse 留存、路徑、漏斗、session 點陣圖 roaringbitmap 點陣圖最佳化Session
- MySQL點陣圖索引解決使用者畫像問題(簡化建立流程)MySql索引
- PHP 文字生成點陣圖PHP
- Redis 應用-點陣圖Redis
- 點陣圖字型匯入
- 可寫點陣圖(WriteableBitmap)
- 慢查詢、pipline、釋出訂閱、 bitmap點陣圖、 hyperloglog、geo、持久化持久化
- PHP掃描圖片轉點陣 二維碼轉點陣PHP
- 演算法-點陣圖排序演算法排序
- 點陣圖與ERP場景
- MySQL的B+Tree索引到底是咋回事?聚簇索引到底是如何長高的?MySql索引
- 代理模式+react+ 圖片佔點陣圖模式React
- layui圖片懶載入-loading佔點陣圖UI
- Oracle中的B樹索引Oracle索引
- Oracle如何建立B樹索引Oracle索引
- 易語言陣列 ,索引從 1 開始。陣列索引
- 淺談MySQL的B樹索引與索引優化MySql索引優化
- hash join構建點陣圖的理解
- VC 點陣圖按鈕CBitmapButton的使用
- 雜湊表擴充套件—點陣圖套件
- DM7 陣列索引陣列索引
- 從點陣圖到布隆過濾器,C#實現過濾器C#
- 搞懂MySQL InnoDB B+樹索引MySql索引
- Oracle如何實現B樹索引Oracle索引
- 深入研究B樹索引(二)索引
- Oracle assm三級點陣圖結構解析OracleSSM
- Android實現二值點陣圖識別Android
- Bitmap Indexing in DBMS Bitmap Index vs. B-tree Index low cardinalityIndex