图26-1 假设我们要找索引中值为80的行,从索引树的最上层入口开始,定位到大于等于50,然后往左找,找到第2个分支块,定位为75-100,最后再定位到叶块上,找到80所对应的rowid,然后根据rowid去读取数据块获取数据。如果查询条件是范围选择的,比如where column >20 and column <80,那么会先定位到第一个包含20的叶块,然后横向查找其他的叶块,直到找到包含80的块为止,不用每次都从入口进去再重新定位。
26.2.2 反向索引 反向索引是B*Tree索引的一个分支,它的设计是为了运用在某些特定的环境下的。Oracle推出它的主要目的就是为了降低在并行服务器(Oracle Parallel Server)环境下索引叶块的争用。当B*Tree索引中有一列是由递增的序列号产生的话,那么这些索引信息基本上分布在同一个叶块,当用户修改或访问相似的列时,索引块很容易产生争用。反向索引中的索引码将会被分布到各个索引块中,减少了争用。反向索引反转了索引码中每列的字节,通过dump()函数我们可以清楚得看见它做了什么。举个例子:1,2,3三个连续的数,用dump()函数看它们在Oracle内部的表示方法。 SQL> select 'number',dump(1,16) from dual 2 union all select 'number',dump(2,16) from dual 3 union all select 'number',dump(3,16) from dual;
'NUMBE DUMP(1,16) ------ ----------------- number Typ=2 Len=2: c1,2 (1) number Typ=2 Len=2: c1,3 (2) number Typ=2 Len=2: c1,4 (3) 再对比一下反向以后的情况: SQL> select 'number',dump(reverse(1),16) from dual 2 union all select 'number',dump(reverse(2),16) from dual 3 union all select 'number',dump(reverse(3),16) from dual;
'NUMBE DUMP(REVERSE(1),1 ------ ----------------- number Typ=2 Len=2: 2,c1 (1) number Typ=2 Len=2: 3,c1 (2) number Typ=2 Len=2: 4,c1 (3) 我们发现索引码的结构整个颠倒过来了,这样1,2,3个索引码基本上不会出现在同一个叶块里,所以减少了争用。不过反向索引又一个缺点就是不能在所有使用常规索引的地方使用。在范围搜索中其不能被使用,例如,where column>value,因为在索引的叶块中索引码没有分类,所以不能通过搜索相邻叶块完成区域扫描。
26.2.3 降序索引 降序索引是8i里面新出现的一种索引,是B*Tree的另一个衍生物,它的变化就是列在索引中的储存方式从升序变成了降序,在某些场合下降序索引将会起作用。举个例子,我们来查询一张表并进行排序: SQL> select * from test where a between 1 and 100 order by a desc,b asc; 已选择100行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=100 Bytes=400) 1 0 SORT(ORDER BY)(Cost=2 Card=100 Bytes=400) 2 1 INDEX (RANGE SCAN) OF 'IND_BT' (NON-UNIQUE) (Cost=2 Card=100 Bytes=400) 这里优化器首先选择了一个索引范围扫描,然后还有一个排序的步骤。如果使用了降序索引,排序的过程会被取消。 SQL> create index test.ind_desc on test.testrev(a desc,b asc); 索引已创建。 SQL> analyze index test.ind_desc compute statistics; 索引已分析 再来看下执行路径: SQL> select * from test where a between 1 and 100 order by a desc,b asc; 已选择100行。 Execution Plan(SQL执行计划,稍后会讲解如何使用)。 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=100 Bytes=400) 1 0 INDEX (RANGE SCAN) OF 'IND_DESC' (NON-UNIQUE) (Cost=2 Card=100 Bytes=400) 我们看到排序过程消失了,这是因为创建降序索引时Oracle已经把数据都按降序排好了。 另外一个需要注意的地方是要设置init.ora里面的compatible参数为8.1.0或以上,否则创建时desc关键字将被忽略。
如果搜索where gender=’Male’,要统计性别是”Male”的列行数的话,Oracle很快就能从位图中找到共3行即第1,9,10行是符合条件的;如果要搜索where gender=’Male’ or gender=’Female’的列的行数的话,也很容易从位图中找到共8行即1,2,3,4,7,8,9,10行是符合条件的。如果要搜索表的值的话,那么Oracle会用内部的转换函数将位图中的相关信息转换成rowid来访问数据块。