知识大全 Oracle位图索引(BitmapIndex)

Posted 索引

篇首语:没有风暴,船帆只不过是一块破布。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Oracle位图索引(BitmapIndex)相关的知识,希望对你有一定的参考价值。

Oracle位图索引(BitmapIndex)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  位图(bitmap)索引是另外一种索引类型 它的组织形式与B树索引相同 也是一棵平衡树 与B树索引的区别在于叶子节点里存放索引条目的方式不同 从前面我们知道 B树索引的叶子节点里 对于表里的每个数据行 如果被索引列的值不为空的 则会为该记录行在叶子节点里维护一个对应的索引条目

  而位图索引则不是这样 其叶子节点里存放的索引条目如下图所示

  假设某个表T里所有的记录在列C 上只具有三个值 和 在表T的C 列上创建位图索引以后 则叶子节点的内容如图 所示 可以看到 位图索引只有三个索引条目 也就是每个C 列的值对应一个索引条目 位图索引条目上还包含表里第一条记录所对应的ROWID以及最后一条记录所对应的ROWID 索引条目的最后一部分则是由多个bit位所组成的bitmap 每个bit位就对应一条记录

  位图索引的结构

  当发出where c = 这样的SQL语句时 oracle会去搜索 所在的索引条目 然后扫描该索引条目中的bitmap里所有的bit位 第一个bit位为 则说明第一条记录上的C 值为 于是返回第一条记录所在的ROWID(根据该索引条目里记录的start ROWID加上行号得到该记录所在的ROWID) 第二个bit位为 则说明第二条记录上的C 值不为 依此类推 另外 如果索引列为空 也会在位图索引里记录 也就是将对应的bit位设置为 即可

  如果索引列上不同值的个数比较少的时候 比如对于性别列(男或女)等 则使用位图索引会比较好 因为它对空间的占用非常少(因为都是用bit位来表示表里的数据行) 从而在扫描索引的时候 扫描的索引块的个数也比较少 可以试想一下 如果在列的不同值非常多的列上 比如主键列上 创建位图索引 则产生的索引条目就等于表里记录的条数 同时每个索引条目里的bitmap里 只有一个 其它都是 这样还不如B树索引的效率高

  如果被索引的列经常被更新的话 则不适合使用位图索引 因为当更新位图所在的列时 由于要在不同的索引条目之间修改bit位 比如将第一条记录从 变为 则必须将 所在的索引条目的第一个bit位改为 再将 所在的索引条目的第一个bit位改为 因此 在更新索引条目的过程中 会锁定位图索引里多个索引条目 也就是同时只能有一个用户能够更新表T 从而降低了并发性

  位图索引比较适合用在数据仓库系统里 不适合用在OLTP系统里

  SQL> create table t_bitmap_test as

   select rownum as id trunc(dbms_random value( )) as bitcol

   from dba_objects where rownum<= ;

  SQL> select * from t_bitmap_test;

  ID     BITCOL

  

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

  SQL> connect hr/hr

  已连接

  SQL> alter session set events trace name context forever level ;

  会话已更改

  SQL> create bitmap index idx_t_bitmap_test on t_bitmap_test(bitcol);

  索引已创建

  SQL> alter session set events trace name context off ;

  会话已更改

  SQL> select object_id from user_objects where object_name= IDX_T_BITMAP_TEST ;

  OBJECT_ID

  

  

  SQL> alter session set events immediate trace name TREEDUMP level ;

  会话已更改

   事件用来跟踪创建bitmap索引的过程 而TREEDUMP则用来转储索引的树状结构 打开转储出来的文件

  *** SESSION ID:( ) : :

  qerbiARwo: bitmap size is

  qerbiIPI default pctfree=

  qerbiIPI length=

  qerbiAllocate pfree= space=

  qerbiStart first start

  qerbiRop: rid= c ce new=Y key: ( ): c

  qerbiCmpSz notfound pctfree=

  qerbiCmpSz adjblksize= length=

  qerbiRop keysize= maxbm=

  kdibcoinit( ): srid= c ce

  qerbiRop: rid= c ce new=Y key: ( ): c

  kdibcoinit( ): srid= c ce

  qerbiRop: rid= c ce new=Y key: ( ): c

  kdibcoinit( c): srid= c ce

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce a new=N key: ( ): c

  qerbiRop: rid= c ce b new=N key: ( ): c

  qerbiRop: rid= c ce c new=N key: ( ): c

  qerbiRop: rid= c ce d new=N key: ( ): c

  qerbiRop: rid= c ce e new=N key: ( ): c

  qerbiRop: rid= c ce f new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  qerbiRop: rid= c ce new=N key: ( ): c

  kdibcoend( ): erid= c ce status=

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca

  kdibcoend( ): erid= c ce status=

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca c

  kdibcoend( c): erid= c ce status=

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca

  这一段是创建bitmap索引的过程 我们先把被索引的列的值换算成十六进制

  SQL> select dump( ) dump( ) dump( ) from dual;

  DUMP( )            DUMP( )            DUMP( )

  

  Typ= Len= : Typ= Len= : Typ= Len= :

   对应的十六进制则是 也就是上面转储部分显示的key部分的键值

  可

  以看到 oracle在创建bitmap索引时 先从第一条记录开始扫描 取出第一条记录的键值(bitcol= ) 也就是 qerbiRop:

  rid= c ce new=Y key: ( ): c

   new=Y说明这是一个新的键值 因此会对应到一个索引条目 扫描第二条记录时 发现bitcol= 该键值也是一个新的键值 因此产生一个新

  的索引条目 对应 qerbiRop: rid= c ce new=Y key: ( ): c

   扫描到第三条记录时 发现bitcol= 该键值也是一个新的键值 因此产生第三个索引条目 对应 qerbiRop:

  rid= c ce new=Y key: ( ): c

  接下来扫描到的记录所对应的bitcol的值都是 中的一个 因此都不会产生新的索引条目 因此它们的new都为N

  然后扫描完表里的所有记录以后 开始创建bitmap索引条目 也就是下面的部分

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca

  kdibcoend( ): erid= c ce status=

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca c

  kdibcoend( c): erid= c ce status=

  qerbiCon: key: ( ): c

  srid= c ce erid= c ce bitmap: ( ): ca

  这里的srid表示start rowid erid表示end rowid

  可以看到总共产生了 个索引条目 其key分别为

  这

   个索引条目的start rowid和end

  rowid的格式分两部分 中间用点隔开 点左边的表示文件号(从左边第一个字节开始的 个字节表示)和数据块号(从左边第五个字节开始的 个字节表

  示) 点右边表示数据块里的行号 这里的显示可以看到 这 条记录都位于相同的数据块里 这里的 c 表示文件号

  SQL> select sys pkg_number_trans f_hex_to_dec( c )/ file# FROM dual;

  FILE#

  

  

  SQL> select sys pkg_number_trans f_hex_to_dec( ce ) as blk# FROM dual;

  BLK#

  

  

  因此这 条记录在 号数据文件的 号数据块里 我们可以使用dbms_rowid来验证

  SQL> select distinct dbms_rowid rowid_relative_fno(rowid) as file#

   dbms_rowid rowid_block_number(rowid) as block#

   from t_bitmap_test;

  FILE#     BLOCK#

  

      

  可以看到 完全符合

  每个索引条目的 bitmap : ( ) 部分表示的也就是前面说到的bit位了 由 组成

  按照前面bitmap的理论 这 条记录所对应的三个索引条目的bitmap的样子应该为

  Key_value    start_rowid    end_rowid      理论上的bitmap         转储文件的bitmap

             c ce     c ce    ca

             c ce     c ce    ca c

             c ce     c ce    ca

  转储文件里的bitmap如何对应到bit位呢 ?首先第一个字节的ca可以不考虑 暂时不知道第一个字节是什么意思 只考虑后三个字节 比如对于key_value= 来说 对应的二进制为

  SQL> col c format a

  SQL> col c format a

  SQL> col c format a

  SQL> select sys pkg_number_trans f_hex_to_bin( ) as c

   sys pkg_number_trans f_hex_to_bin( ) as c

   sys pkg_number_trans f_hex_to_bin( ) as c from dual;

  C          C          C

  

             

  其中不足 位的前面用 补齐 因此 C = C = C =

  在二进制里 每个应该倒过来 从右到左排列 因此为

  C          C         C

        

  然后将它们组织为一个由多个bit位组成的bitmap的话 仍然从右到左 依次取出每个bit位 于是我们有 我们可以把这个bit串与理论上的bitmap比较一下

  

  

  很明显 除了最后多出来的 个 以外 其余部分完全一致 而最后多出的 并不影响这个索引条目的使用

  类似的 我们可以使用相同的方法来依次验证另外两个键值 都是符合理论值的

  数据都在一个数据块里的情况比较容易理解 如果被索引的数据分布在多个数据块里呢?

  经常会有人问到 只记录start rowid和end rowid 如果被索引的记录分布在多个数据块里 那么oracle如何根据start rowed来找到bitmap里的bit= 所对应的记录的rowid呢?

  创建一个表

  SQL> create table t_bitmap_ (id number bitcol char( ));

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( A );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( B );

  insert into t_bitmap_ values( B );

  MIT;

  获得这 条记录所在的数据块号

  SQL> select distinct dbms_rowid rowid_relative_fno(rowid) as file#

   dbms_rowid rowid_block_number(rowid) as block#

   from t_bitmap_ ;

  FILE#     BLOCK#

  

         

         

         

         

         

         

  可以知道 这 条记录分布在 个数据块里

  然后跟踪对于bitcol列上的bitmap索引的创建过程

  alter session set events trace name context forever level ;

  create bitmap index idx_t_bitmap_ on t_bitmap_ (bitcol);

  alter session set events trace name context off ;

  从转储出来的文件可以看到 最终形成了两个索引条目

  ……

  qerbiCon: key: ( ):

  

  ……

  srid= c d erid= c d bitmap: ( ): c c f b f

  ……

  qerbiCon: key: ( ):

  

  ……

  srid= c d erid= c d bitmap: ( ): f f c a c

  *** : :

  很明显 这里的两个索引条目的start rowed和end rowed是不相同的

  键值为A的索引条目为

  srid= c d erid= c d bitmap: ( ): c c f b f

  其数据块从 d 到 d 也就是

  SQL> select sys pkg_number_trans f_hex_to_dec( d ) as s_blk#

   sys pkg_number_trans f_hex_to_dec( d ) as e_blk#

   from dual;

  S_BLK#     E_BLK#

  

      

  而键值B的索引条目为

  srid= c d erid= c d bitmap: ( ): f f c a c

  其数据块从 d 到 d 也就是

  SQL> select sys pkg_number_trans f_hex_to_dec( d ) as s_blk#

   sys pkg_number_trans f_hex_to_dec( d ) as e_blk#

   from dual;

  S_BLK#     E_BLK#

  

         

  这个时候

  SQL> select substr(bitcol ) as bitcol dbms_rowid rowid_block_number(rowid) as block# from t_bitmap_ ;

  BI     BLOCK#

  

  B       

  A       

  A       

  A       

  B       

  B       

  B       

  B       

  B       

  A       

  A       

  A       

  B       

  A       

  A       

  B       

cha138/Article/program/Oracle/201311/17926

相关参考

知识大全 位图索引的故事

  您如果熟悉Oracle数据库我想您对ThomasKyte的大名一定不会陌生Tomas主持的网站享誉Oracle界数十年绝非幸致最近在图书馆借到这位Oracle绝顶高手编著的《ExpertOracl

知识大全 各种索引的结构分析降序索引和位图索引

  降序索引  降序索引是i里面新出现的一种索引是B*Tree的另一个衍生物它的变化就是列在索引中的储存方式从升序变成了降序在某些场合下降序索引将会起作用举个例子我们来查询一张表并进行排序  SQL&

知识大全 Oracle索引原理

Oracle索引原理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Oracle提供了大量索引选

知识大全 ORACLE索引提高效率

ORACLE索引提高效率  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  用索引提高效率  索引是

知识大全 Oracle监控索引怎么使用

Oracle监控索引怎么使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Oracle监控索引

知识大全 Oracle在线索引重构

Oracle在线索引重构  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  查询某个表的索引属于哪个

知识大全 oracle数据库如何重建索引

  当索引的碎片过多时会影响执行查询的速度从而影响到我们的工作效率这时候采取的最有利的措施莫过于重建索引了本文主要介绍了Oracle数据库中检查索引碎片并重建索引的过程接下来我们就开始介绍这一过程  

知识大全 Oracle索引(index)简单介绍

Oracle索引(index)简单介绍  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  索引分类 

知识大全 Oracle索引的内部结构

Oracle索引的内部结构  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Oracle使用平衡树

知识大全 oracle修改索引现有表空间

  //dba_indexes可查询所有索引以及索引部分信息可以灵活运用于其他用途  //假设用户USER现有表空间TSTS需要迁移其下所有表空间TS的索引到TS中可使用以下语句(在plsql中)