在数据库操作中,我们该如何避免大型数据表扫描、全数据表扫描和磁盘排序等既费时间又费力气的操作呢?Oracle9i对这一问题的回答是:采用索引技术,显然,在SQL优化器无法找到有效的方式来完成SQL查询的情况下就要用到索引运算了。我们首先看一下Oracle9i索引中标准的Oracle b-tree索引方法。
显然,b-tree 索引通常是非常适合进行简单的单一查询的,但是在以下条件下就不适合选择这种方法了:
- 列的基数较低—可区分值少于200个的列无须采用标准的b-tree索引结构。
- 不支持SQL函数—B-tree索引不能采用Oracle的内置函数来支持SQL查询。而Oracle9i提供了各种内置函数,通过它们可以让SQL表达式查询部分索引列。
在Oracle9i问世之前,由于以上的缺陷,在很多情况下,Oracle SQL优化器不得不执行费时的长表、全表扫描。Oracle当然认识到了这一点,自然在新版数据库中引入了更为稳固的索引结构类型。
名称 |
含义 |
Non-Unique |
非惟一索引,默认的B-树索引,索引列值可以不是惟一的 |
Unique |
惟一索引,在创建索引时指定“UNIQUE”关键字可以创建惟一索引。当建立“主码约束条件”时也会建立惟一索引,索引列值是惟一的 |
Reverse Key |
反向关键字索引,通过在创建索引时指定“REVERSE”关键字,可以创建反向关键字索引,被索引的每个数据列中的数据都是反向存储的,但仍然保持原来数据列的次序 |
Function-based |
基于函数的索引,对数据列使用表达式,按照表达式结果来创建B-树索引的各节点,适合特定的,经常使用该表达式进行类似查询的数据表的索引的组织 |
位图索引
位图索引特别适用于表内包含多个位图索引这种情况:每个单列都可能会有较低的基数。创建多个位图索引这种方法就可以更快的速度决绝SQL查询所面临的困难。
再如,假设现在有一个汽车数据库,其中包含了大量的低基数列,比如car_color、car_make、car_model和car_year等。以上这些列各自包含的值数目不超过100,b-tree索引在一个包含2000万辆汽车数据的数据库面前毫无用处。但是,把这些索引组合到一个查询里就会相比传统查询读取表内2000万行记录的速度要快得多。比如,假设我们想找出1981年生产的老式Toyota Corollas汽车,其查询情况请见清单B。
Oracle采用了专门的优化器把位图索引合并起来服务于查询操作。在位图索引合并的情况下,每一个Row-ID或者说RID列表都采用位图独立创建,一种专门的合并程序则用来比较RID列表同时找出交叉值。采用这种方法,Oracle就可以在处理多个低基数列的同时实现更快的响应时间(请参看图B)。
函数索引
Select * from customer where substr(cust_name,1,4) = ‘BURL’;
Select * from customer where to_char(order_date,’MM’) = ’01;
Select * from customer where upper(cust_name) = ‘JONES’;
Select * from customer where initcap(first_name) = ‘Mike’;
在Oracle9i系统下,Oracle总会检查SQL 表达式的where子句查看是否存在匹配的索引。在基于函数的索引这一情况下,Oracle设计人员可以创建用SQL where语句准确判断的匹配索引。这样就保证了查询可以最低程度的磁盘读写和最快的速度得到结果。
唯索引表
Oracle用唯索引表结构(IOT)实现了以上的想法。在使用IOT的情况下,Oracle并不创建实际的表而是把所有需要的信息都保存在Oracle索引之内。在查询的时候,Oracle SQL优化器在索引树内找出服务于现有查询的所有必要的值,此时,Oracle根据查询代价的优化器选择读取索引树节点然后按序取出数据或者调用索引快速全扫描,后者将用全表扫描同样的方式采用连续预取(由db_file_multiblock_read_count参数定义)方法读取数据表。Multiblock读取工具可以让Oracle很快地线性扫描索引块,快速地读取索引表空间内的每一块。清单C就包括了创建IOT的语法示例。