Oracle 索引的介绍

来源:互联网 发布:网络发票验旧系统 编辑:程序博客网 时间:2024/05/20 06:38

 一、索引的概念:

    索引是建立在表上的可选对象。

    索引的关键在于通过一组排序后的索引键(rowid)来取代默认的全表扫描检索方式,从而提高检索效率。

    索引在逻辑上和物理上都与相关的表的数据无关,当创建或删除一个索引时,不会影响基本的表、数据库应用或其他索引,当插入、更改和删除相关的表记录时,Oracle会自动管理索引,如果删除索引,所有的应用仍然可以继续工作。因此,在表上创建索引不会对表的使用产生任何影响,但是,在表中的一列或多列上创建适当的索引可以为数据的检索提供快捷的存取路径,提高检索速度。

 

二、索引的分类:

1.按照存储方式分为B-Tree索引,反向索引,位图索引。
2.按照索引列的个数分为单列索引和复合索引。
3.按照索引的唯一性可以分为惟一索引和非惟一索引。

 

三、索引的结构与原理:

1.B-Tree索引:

   B-Tree索引是最常见的索引结构,默认创建的索引就是B-Tree索引。是基于二叉树结构的。分为根节点、分支节点、叶子节点几块组成。

   叶子节点(Leaf node):包含条目直接指向表里的数据行。
   分支节点(Branch node):包含的条目指向索引里其他的分支节点或者是叶子节点。
    根节点(Branch node):一个B树索引只有一个根节点,它实际就是位于树的最顶端的分支节点。



 

    对于分支节点块(包括根节点块)来说,其所包含的索引条目都是按照顺序排列的(缺省是升序排列,也可以在创建索引时指定为降序排列)。每个索引条目(也可以叫做每条记录)都具有两个字段。第一个字段表示当前该分支节点块下面所链接的索引块中所包含的最小键值;第二个字段为四个字节,表示所链接的索引块的地址,该地址指向下面一个索引块。在一个分支节点块中所能容纳的记录行数由数据块大小以及索引键值的长度决定。比如从上图一可以看到,对于根节点块来说,包含三条记录,分别为(0 B1)、(500 B2)、(1000 B3),它们指向三个分支节点块。其中的0、500和1000分别表示这三个分支节点块所链接的键值的最小值。而B1、B2和B3则表示所指向的三个分支节点块的地址。也就是说,Oracle在 Branch block中只记录 索引键值的前缀,而不是所有值,是因为这样可以节约空间,从而能够存储更多的索引条目。同时,我们也能理解了为什么 查询使用like '%xxx' 这种方法不会走Btree 索引,因为Branch block 存储的是前缀。

    对于叶子节点块来说,其所包含的索引条目与分支节点一样,都是按照顺序排列的(缺省是升序排列,也可以在创建索引时指定为降序排列)。每个索引条目(也可以叫做每条记录)也具有两个字段。第一个字段表示索引的键值,对于单列索引来说是一个值;而对于多列索引来说则是多个值组合在一起的。第二个字段表示键值所对应的记录行的ROWID,该ROWID是记录行在表里的物理地址。如果索引是创建在非分区表上或者索引是分区表上的本地索引的话,则该ROWID占用6个字节;如果索引是创建在分区表上的全局索引的话,则该ROWID占用10个字节。

      例:假设我们要找索引中值为80的行,从索引树的最上层入口开始,定位到大于等于50,然后往左找,找到第2个分支块,定位为75100,最后再定位到叶块上,找到80所对应的rowid,然后根据rowid去读取数据块获取数据。如果查询条件是范围选择的,比如where column >20 and column <80,那么会先定位到第一个包含20的叶块,然后横向查找其他的叶块,直到找到包含80的块为止,不用每次都从入口进去再重新定位。

 

 2.bitmap索引:

       位图(bitmap)索引是另外一种索引类型,它的组织形式与B树索引相同,也是一棵平衡树。与B树索引的区别在于叶子节点里存放索引条目的方式不同。从前面我们知道,B树索引的叶子节点里,对于表里的每个数据行,如果被索引列的值不为空的,则会为该记录行在叶子节点里维护一个对应的索引条目。
而位图索引则不是这样,其叶子节点里存放的索引条目如下图所示。
       假设某个表T里所有的记录在列C1上只具有三个值:010203。在表TC1列上创建位图索引以后,则叶子节点的内容如图所示。可以看到,位图索引只有三个索引条目,也就是每个C1列的值对应一个索引条目。位图索引条目上还包含表里第一条记录所对应的ROWID以及最后一条记录所对应的ROWID。索引条目的最后一部分则是由多个bit位所组成的bitmap,每个bit位就对应一条记录。

       当发出where c1='01'这样的SQL语句时,oracle会去搜索01所在的索引条目,然后扫描该索引条目中的bitmap里所有的bit位。第一个bit位为1,则说明第一条记录上的C1值为01,于是返回第一条记录所在的ROWID(根据该索引条目里记录的start ROWID加上行号得到该记录所在的ROWID)。第二个bit位为0,则说明第二条记录上的C1值不为01,依此类推。另外,如果索引列为空,也会在位图索引里记录,也就是将对应的bit位设置为0即可。
       如果索引列上不同值的个数比较少的时候,比如对于性别列(男或女)等,则使用位图索引会比较好,因为它对空间的占用非常少(因为都是用bit位来表示表里的数据行),从而在扫描索引的时候,扫描的索引块的个数也比较少。可以试想一下,如果在列的不同值非常多的列上,比如主键列上,创建位图索引,则产生的索引条目就等于表里记录的条数,同时每个索引条目里的bitmap里,只有一个1,其它都是0。这样还不如B树索引的效率高。
       如果被索引的列经常被更新的话,则不适合使用位图索引。因为当更新位图所在的列时,由于要在不同的索引条目之间修改bit位,比如将第一条记录从01变为02,则必须将01所在的索引条目的第一个bit位改为0,再将02所在的索引条目的第一个bit位改为1。因此,在更新索引条目的过程中,会锁定位图索引里多个索引条目。也就是同时只能有一个用户能够更新表T,从而降低了并发性。
       位图索引比较适合用在数据仓库系统里,不适合用在OLTP系统里。位图索引主要用于决策支持系统或静态数据,不支持行级锁定,位图索引最好用于低基数列(字段值较少的列)

          例如:Create bitmap indexinx_bitmap_emp onemp(sex);

 

*索引建设原则:具体原则请参照http://blog.csdn.net/gybyylx/article/details/7557625

  1. 结合实际的应用。
  2. 考虑索引列的数据分布,如果distinct值很少且数据分布均匀的话,可能就不适合放在联合索引的最前面。
  3. 考虑索引的大小,在字段长度32的列和长度为7的列上建立索引大小肯定是不一样的,索引越大扫描的代价就越高。
  4. 考虑索引列冗余,可能你在索引中多冗余一个小字段,select就只走索引而不需要去扫描原表的数据。
  5. 考虑索引对其他sql的影响,是否其他的sql也可以使用这个索引。
  6. 考虑对是否可以对原有索引进行合并,评估合并会有多大的影响。

 

 

原创粉丝点击