索引的类型

本文所属图书 > Oracle数据库性能优化的艺术

为了应对不同的数据操作场景,Oracle提供了若干对应的索引类型,主要的几种类型如下:

B树索引
位图索引
索引组织表
逆序索引
函数索引
哈希索引
分区索引(本地和全局索引)
1. B树索引
B树索引是关系 数据库中最基本的索引结构,也是 Oracle 系统中最常见的索引形式。Oracle提供的B树索引既可以用来索引 数据库表中的一个数据列,也可以用来索引两个以上的数据列组合,此为组合索引形式。
如图2-21所示的示例中,B树索引共分为三层(高度为3),根节点指向枝节点,但最终会到达带有ROWID信息的叶节点。叶节点则包含了被索引的数据值(一个ROWID),ROWID指向数据所在的具体位置(即在哪一个Oracle数据文件、文件中哪一个盘区、盘区中哪一个数据块)。不仅如此,叶节点还保存着指向前一个叶节点和后一个叶节点的指针,它们用于从两个方向遍历,执行范围类扫描。

\
图2-21 Oracle B树索引采用的数据结构
对于具有高可选择性的列来说,采用B树形式的索引来定位数据是较好的选择。
2. 位图索引
位图索引是按照“位”来索引表中记录的取值的。这是一种主要用于OLAP系统(如数据仓库)类应用的索引结构,其结构示意图如图2-22所示。
\
在图2-22中,表中包含了一个称为客户级别的列,它有若干个取值(大约几十个)。因此,如果对该列进行索引,并且索引采用B树结构存储,则该列的可选择性会很低。但如果是通过位图的索引方式,例如查看级别为30的客户名单(如图2-22所示),我们就可以知道:第三个、第四个、第五个、第六个客户的级别就是30。这样做可以快速缩小结果集,得到查询结果。
但是不要忘了该类型索引的维护代价。如果表中持续发生数据改变(如持续新增客户),则数据库在维护这个分布位图时将要付出很大的代价。同时,由于位图索引是按位存储索引值的,每个索引值会映射一个范围的ROWID,因此在更新时Oracle会锁定这个范围内的所有ROWID,造成其他一些DML语句锁申请等待,甚至发生死锁。当多用户并行执行更新时,其瓶颈效果会很明显。
正因为如此,如果在联机事务处理类型的应用中使用位图索引,则应关注这个表的更新频率和更新方式。就应用场景而言,位图索引更适合于数据仓库类的系统,而非事务处理类型的应用。其适用范围是表中列的取值较少(基数小)但行数非常大的表。例如,表中存在的“性别”列,其取值只有“男”、“女”两项(基数很小),但该表行数却很多,同时,“性别”这列又是常用的查询条件列。
3. 索引组织表
如果数据库实体表的定义非常“简短”,则Oracle支持将该表直接按照B树索引的方式存储,存储时以表的主键值排序。从外观上来看,这种表和其他类型的表一样都会正常接受SQL的访问,包括任意DSL、DML和DDL语句的执行。索引组织表的结构如图2-23所示。
\

图2-23 Oracle独有的索引组织表结构
由于B树索引结构有利于执行那些精确的行数据匹配和范围匹配的SQL语句,因此,索引组织表形式有利于基于表主键列访问的应用,这对于SELECT语句,以及UPDATE和DELETE语句来说,性能都可以得到提高。同时,由于索引组织表的数据存储在物理上是有序的,键列又是唯一的,因此索引组织表所需的存储空间也会相应减少,这又有利于降低I/O上的操作。
另外,虽然索引组织表以主键列为索引列进行了索引化的存储,但这并不会影响对该表执行其他非主键列的数据查询。同时还可以在表的其他列上创建额外索引,以利于其他SQL的操作。
所以,对“简短的”表按照索引组织结构进行存储,是一种对表进行物理部署优化的具体方式。
4. 逆序索引
通常,数据库中的很多表会以数据单调递增的列作为主键,例如,超市系统记载水单的“流水号”数据。这种数据具有连续递增的特性,在编程时往往会用序列号对象(sequence object)生成流水号。
这种表的存储特征是,数据列的数据是单调、连续递增的,且物理存储接近,同时,该列的索引也是有序和连续的。也就是说,这种表存在表数据连续、索引数据连续的“并行”特征。
这就会造成数据操作时的热点I/O问题,尤其在表已经载入一定量的数据时,其效果如图2-24所示。

图2-24 连续的索引I/O源于连续的数据更新操作
因此,普通的B树索引,在这种情况下会碰到与I/O争用相关资源的一些瓶颈问题。所谓逆序索引,就是为了解决这类问题而在索引中对Oracle表数据所进行的一个逆序转换。例如,表中的数据1000在索引中会变成0001,而表中的数据1001在索引中将变成1001。这样,表中连续的数据1000、1001在索引中就成为了不连续的0001、1001。
逆序索引对于这种具有连续特征的数据表来说,在消减与其关联的I/O热点、锁等待方面是很有效的。
5. 函数索引
在Oracle执行计划的制定中,Oracle的优化器不能对已经进行了函数处理的WHERE条件设置索引扫描路径。例如下面的SQL语句:
select col1,col2,... from table where function(col1)=:x;
虽然我们可能已经在表table的col1列上建立了完整的索引,但由于WHERE条件中function()函数对col1列的处理,使得Oracle优化器将不会考虑使用col1列上的索引。不仅是Oracle,其他的数据库也基本如此。
为了应对这种情况,Oracle采取了创建一种特殊索引的方法—针对函数处理过的列进行索引。就拿上例来说,我们可以针对function(col1)进行索引,这就是函数索引。如果这个索引已经存在,则前面示例中的SQL语句将有可能会使用这个索引。
前面多次提到,任何索引都是把双刃剑,不过,函数索引这把剑的“内刃”可能要更为锋利一些。为什么呢?如果表中的数据发生更改,索引中的数据在同步时就需要调用这个函数来进行维护,所以性能上的损失比一般的B树索引要大一些。
另外,一个函数索引只能解决这个函数在查询中存在的调用问题,如果换成另外一个函数调用,则这个函数索引将会失效。
所以,使用函数索引要更加小心,防止弊大于利的结果发生,在建立它们之前应考虑如下的问题:
是否需要函数索引?数据库分析设计中列的设计是否存在问题,为什么列需要用函数来处理?
索引导致的空间存储增加是否值得?
函数索引的增加会对该表上执行的DML语句带来性能上的负面影响,可否接受这种影响?
虽然函数索引在某些场景下是非常有用的,但函数索引技术的使用不具有普遍意义(换句话说,不使用函数索引是具有普遍意义的)。我们在使用时要小心其副作用,表上的索引越多,则DML操作(INSERT、UPDATE、DELETE)越慢,函数索引更是如此。
对于Oracle优化器来说,如果使用函数索引,则需要将其初始参数query_rewrite_enabled设定为TRUE(这是默认值)。
6. 哈希索引
对于Oracle的簇表来说,在创建簇之前,需要先行创建一个哈希索引(如果是哈希簇)。有关哈希簇的设计和实现请参见其他的技术资料。
7. 分区索引
对于Oracle分区表来说,部署在分区表上的索引也可能被分区(分区化对等实现)处理,用于索引那些分区内的数据。分区索引的设计和实现参见第9章
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值