频道栏目
读书频道 > 数据库 > Oracle > 高并发Oracle数据库系统的架构与设计
2.1.9 索引组合扫描
2014-11-28 14:29:37     我来说两句
收藏   我要投稿
Foreword?推 荐 序 一文以载道 书以自娱侯松的新书付梓,嘱我为序,品读精华章节,览其前言,心有所感,遂言而记之。关于写作之因由,于作者来说,一直是最为重要的缘起。认真地写作一本好书,其中的坚持、勤  立即去当当网订购
如果一个查询语句中,WHERE子句包含两个筛选条件,这两个条件都有其单独的索引,我们是不是可以同时使用两个索引呢?答案是肯定的。我们可以通过两个独立的索引分别扫描,再组合起来。在Oracle早期的版本中,我们可以通过and_equal方式来实现。从Oracle 10g开始,and_equal方式已经被废弃,由index_combine方式取而代之。
 
索引组合(INDEX COMBINE)最早是出现在位图索引上的,从Oracle 9i开始,默认可以使用在B树索引上,这个特性是由隐藏参数_b_tree_bitmap_plans来控制的。Oracle将B树索引中获得的ROWID信息通过BITMAP CONVERSION FROM ROWIDS的步骤转换成位图进行匹配,完成后通过BITMAP CONVERSION TO ROWIDS再转换出ROWID获得数据或者回表获得数据。
 
通过一个例子来看一下吧。在开始之前,我们需要修改一下表alex_t01上的索引,我们需要删除掉组合索引idx_alex_t01_id_ab,为b列创建一个单列索引idx_alex_t01_id_b,并重新收集统计信息。SQL语句如下:
SQL> drop index idx_alex_t01_id_ab;
SQL> create index idx_alex_t01_id_b on alex_t01 (b);
SQL> exec dbms_stats.gather_index_stats('alex','idx_alex_t01_id_b')
此时,b列和c列都有了其独立的单列索引,且此两列区分度都较高。我们再来做一次基于b列和c列的组合查询试试:
SQL> select * from alex_t01 where b=600 and c=600;
-------------------------------------------------------------------------------------------
| Id  | Operation                        | Name              | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                   |     1 |    21 |     2   (0)|
|   1 |  TABLE ACCESS BY INDEX ROWID     | ALEX_T01          |     1 |    21 |     2   (0)|
|   2 |   BITMAP CONVERSION TO ROWIDS    |                   |       |       |            |
|   3 |    BITMAP AND                    |                   |       |       |            |
|   4 |     BITMAP CONVERSION FROM ROWIDS|                   |       |       |            |
|*  5 |      INDEX RANGE SCAN            | IDX_ALEX_T01_ID_B |     5 |       |     1   (0)|
|   6 |     BITMAP CONVERSION FROM ROWIDS|                   |       |       |            |
|*  7 |      INDEX RANGE SCAN            | IDX_ALEX_T01_ID_C |     5 |       |     1   (0)|
-------------------------------------------------------------------------------------------
 
如果你因为看到BITMAP CONVERSION的字样而感到担忧的话,那大可不必,这部分的COST基本可以忽略,这是一个典型的index_combine例子。
 
我们要是强制查询只走其中一个索引呢,情况会如何呢?看一个示例:
SQL> select /*+index(alex_t01,idx_alex_t01_id_b)*/ * 
2  from alex_t01 where b=600 and c=600;
--------------------------------------------------------------------------------------
| Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   |     1 |    21 |     6   (0)|
|*  1 |  TABLE ACCESS BY INDEX ROWID| ALEX_T01          |     1 |    21 |     6   (0)|
|*  2 |   INDEX RANGE SCAN          | IDX_ALEX_T01_ID_B |     5 |       |     1   (0)|
--------------------------------------------------------------------------------------
 
SQL> select /*+index(alex_t01,idx_alex_t01_id_c)*/ * 
2  from alex_t01 where b=600 and c=600;
--------------------------------------------------------------------------------------
| Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   |     1 |    21 |     6   (0)|
|*  1 |  TABLE ACCESS BY INDEX ROWID| ALEX_T01          |     1 |    21 |     6   (0)|
|*  2 |   INDEX RANGE SCAN          | IDX_ALEX_T01_ID_C |     5 |       |     1   (0)|
--------------------------------------------------------------------------------------
 
从上例可以看到,不论是走b列的索引还是走c列的索引,其COST开销都不如index_combine方式更优。
 
换而言之,如果我们知道索引组合扫描的方式会更优,也可以通过给SQL语句添加HINT关键字的方式,改变执行计划,强制SQL语句走索引组合扫描,示例如下所示:
SQL> select /*+ index_combine(alex_t01 idx_alex_t01_id_b
  2  idx_alex_t01_id_c) */ * from alex_t01 where b=600 and c=600;
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:2.1.8 索引跳跃扫描
下一篇:2.1.10 索引联立扫描
相关文章
图文推荐
排行
热门
最新书评
特别推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站