11.3 B-树 索引
尽管Oracle中所有的索引都使用B-树结构,但是B-树索引这一术语通常是指如图11-1所示的索引。
图11-1
根据图11-1所示:索引的顶端是根结点,这一结点中包含的是存有指向索引中下一级指针的项。接下来是分枝结点(块),分枝结点中的记录(项)存的是指向下一级(块)的指针。最底层为叶子结点。在叶子结点存有指向表中数据行的索引项。叶子结点被双向链表链在一起以方便按索引关键字的升序或降序扫描。
介绍完了B-树索引的整体结构,现在来介绍索引叶子结点的索引项(记录)的内部结构。索引项(记录)是由三部分组成的,它们是:
Ø 索引项头(Entry Header):存储了行数和锁的信息。
Ø 索引列长度和值:必须成对出现,它定义了列的长度,紧跟在长度之后的就是列的值。
Ø ROWID:指向表中数据行的ROWID。
在非分区表上B-树索引中的叶子结点的索引项(记录)具有如下的特性:
Ø 如果具有相同索引键值的数据行有多行而且索引没有被压缩,索引键值会重复存放。
Ø 所有索引所在列的值为空(NULL)的数据行,Oracle将不存储与之对应的索引项。因此,如果在WHERE子句中索引所在列的值为NULL,Oracle将不使用索引而进行全表扫描。
Ø 用于指向数据行的是限制性ROWID,因为所有的数据行都属于相同的段。在索引项使用限制性ROWID的好处是节省了索引的存储空间。
当对表进行DML操作时,Oracle服务器将自动地维护基于该表的全部索引。其维护的方法如下:
Ø 当对表进行插入(INSERT)操作时,在对应的索引数据块中插入一行索引项。
Ø 当对表进行删除(DELETE)操作时,Oracle服务器仅对索引项进行逻辑删除操作。即仅在所删除的索引项上加一个标记并不真正地删除这一项,而只有等该块中所有的项都被删除后才真正地删除它们。
Ø 当对表进行修改(UPDATE)操作时,Oracle服务器实际上对索引进行的是两个操作,一个是逻辑删除操作而另一个是插入操作。
介绍完了B-树索引,下面我们将开介绍Oracle中可能经常使用的另一种索引的结构,位图索引。
11.4 位图索引
与B-树索引相比,在某些情况下位图索引具有更多的优势。位图索引也是一种B-树结构,但是位图索引的叶子结点存的不是ROWID而是每一个键值的位图。以下图11-2就是位图索引的一个结构示意图。
图11-2
根据图11-2所示:位图中的每一位对应着一个可能的ROWID,如果这一位被置位就意味着ROWID所对应的行中包含键值。其中位图索引的叶子结点包含了如下部分:
Ø 索引项头(Entry Header):存储了行数和锁的信息。
Ø 键值(Key Values):由索引列的长度和值所组成。在图11-2的例子中,索引键仅由一列所组成,并且它的最后一个索引项的键值为“壮士”。
Ø 起始ROWID:为位图的起始地址,即位图中第一行的ROWID。包括相对文件号,在相对文件中的块号,和块中的行号。
Ø 终止ROWID:为位图的终止地址,即位图中最后一行的ROWID。也包括相对文件号,在相对文件中的块号,和块中的行号。
Ø 位图段(Bitmap segment):是由一串位所组成的。如果某一位置位(为1),就表示该位所对应的行包含索引的键值。如果该位没有被置位(为0),就表示该位所对应的行不包含索引的键值。Oracle服务器使用一个有专利的压缩技术对位图段进行压缩之后再存储,所以位图索引可能会节省大量的存储空间。
下面我们按照图11-2所示的位图,给出一个实用的解释:
请看键值为学士的第一行:
位图是从第4号文件的第14(数据)块的第0行开始到第4号文件的第16(数据)块的第8行结束。位图中的第一行记录为学士(因为位图中相应位是1),第二行不是学士,第三行也不是,第四行也不是,但第五行是,以此类推。
接下来请看键值为壮士的最后一行:
位图也是从第4号文件的第14(数据)块的第0行开始到第4号文件的第16(数据)块的第8行结束。位图中的第一行记录不是壮士(因为位图中相应位是0,其实该行已经是学士了当然也就不可能再是壮士了),第二行不是壮士(因为该行已经是博士了当然也就不可能再是壮士了),第三行才是壮士(因为位图中相应位是1),以此类推。
如果读者对此感兴趣,可以使用上述更加详细地方法分析图11-2所示的位图。
11.5 B-树索引和位图索引的比较
介绍了这么多的B-树索引和位图索引,那么这两种索引之间究竟有哪些差别呢?表11-1给出了它们比较结果的一个总结。
表11-1
下面我们来详细解释图表11-1给出的结论。我曾查阅了几本英语字典想找到cardinality的确切中文意思,但是没找到一个令我满意的答案。在这里low-cardinality的含义就是列的值可以枚举,如性别和婚姻状况,以及我们例子中的学位。而high-cardinality的含义就是列的值很难枚举,如人名等。
从上一节所介绍的位图索引的存储结构可知:对于low-cardinality的列使用位图索引要比B-树索引紧凑得多,从而节省大量的磁盘空间,这也就减少了输入/输出量,也达到了提高系统效率的效果。
另外,由于位图索引所需要的存储空间要比B-树索引的小得多,所以一般Oracle服务器在使用位图索引时将整个位图索引段装入内存中。这实际上是将一个在磁盘上的搜索过程变成了一个内存查找过程,从而大大地提高了系统的效率。Oracle是用初始化参数文件中的参数CREATE_BITMAP_AREA_SIZE来定义这个内存区的大小的。其默认值为8 MB。
读者要注意的是:在图表11-1中所说的B-树索引对关建字列的修改相对不算昂贵,并不是真的不昂贵,只是与位图索引相比较才不算昂贵,其实DML操作对任何类型的索引都很昂贵。在位图索引中修改键值列(索引列)需要使用段一级的锁,而B-树索引是使用的行一级的锁,还有在这种情况下可能要调整位图。因此在位图索引中对关建字列的修改是非常昂贵。
在对位图索引进行逻辑操作时,Oracle服务器使用的是位操作,因此位图索引进行逻辑操作效率是非常高的。
最后的结论是:B-树索引可能更适合于联机事务处理(OLTP)系统,因为在联机事务处理系统中DML操作频繁。位图索引可能更适合于数据仓库(Data Warehouse)系统,因为在数据仓库系统中表一般都较大但是为静态的并且查询较为复杂。