zoukankan      html  css  js  c++  java
  • index_combine and index_john

     

    and_equalOracle支持的一种特定操作,可以将多个单列索引进行合并(Index Merge)输出查询结果。
    同时and_equal可以通过Hints来进行强制,最少指定两个索引,最多指定5个。

    以下的执行计划是常见的and_equal执行方式:

    SQL> select /*+ and_equal(t1 iu ii) */  username,password from t1 where username='EYGLE' and user_id=58;

    USERNAME                       PASSWORD
    ------------------------------ ------------------------------
    EYGLE                          B726E09FE21F8E83


    执行计划

    ----------------------------------------------------------
    Plan hash value: 1425017857

    ------------------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |     1 |    47 |     2   (0)| 00:00:01 |
    |*  1 |  TABLE ACCESS BY INDEX ROWID| T1   |     1 |    47 |     2   (0)| 00:00:01 |
    |   2 |   AND-EQUAL                 |      |       |       |            |          |
    |*  3 |    INDEX RANGE SCAN         | II   |     1 |       |     1   (0)| 00:00:01 |
    |*  4 |    INDEX RANGE SCAN         | IU   |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       1 - filter("USERNAME"='EYGLE' AND "USER_ID"=58)
       3 - access("USER_ID"=58)
       4 - access("USERNAME"='EYGLE')

    但是从Oracle 10g开始,and_equal操作被废弃(depricated)掉,Oracle不再支持。这里废弃的含义并不是被彻底移除,而是说不再进行改进,通过hints仍然可以强制实现Index Merge的and_equal操作。

    以上的输出就是来自Oracle 10.2.0.4,在使用rule提示时,Oracle会主动选择and_equal,所以不再支持是因为,这种方法限制过多,而且远不如复合索引来的灵活:

    SQL> select * from v$version;

    BANNER
    ----------------------------------------------------------------
    Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
    PL/SQL Release 10.2.0.4.0 - Production
    CORE    10.2.0.4.0      Production
    TNS for 32-bit Windows: Version 10.2.0.4.0 - Production
    NLSRTL Version 10.2.0.4.0 - Production


    SQL> select /*+ rule */  username,password from t1 where username='EYGLE' and user_id=58;

    USERNAME                       PASSWORD
    ------------------------------ ------------------------------
    EYGLE                          B726E09FE21F8E83


    执行计划

    ----------------------------------------------------------
    Plan hash value: 3072843751

    --------------------------------------------
    | Id  | Operation                   | Name |
    --------------------------------------------
    |   0 | SELECT STATEMENT            |      |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1   |
    |   2 |   AND-EQUAL                 |      |
    |*  3 |    INDEX RANGE SCAN         | IU   |
    |*  4 |    INDEX RANGE SCAN         | II   |
    --------------------------------------------

    新的可选替代方案是NDEX_COMBINE,从9i开始,初始化参数 _b_tree_bitmap_plans设置为true,允许为B*Tree索引使用,bitmap convert:

    SQL> select /*+ index_combine(t1 iu ii) */  username,password from t1 where username='EYGLE' and user_id=58;

    USERNAME                       PASSWORD
    ------------------------------ ------------------------------
    EYGLE                          B726E09FE21F8E83


    执行计划

    ----------------------------------------------------------
    Plan hash value: 1808973554

    -----------------------------------------------------------------------------------------
    | Id  | Operation                        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                 |      |     1 |    47 |     2   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID     | T1   |     1 |    47 |     2   (0)| 00:00:01 |
    |   2 |   BITMAP CONVERSION TO ROWIDS    |      |       |       |            |          |
    |   3 |    BITMAP AND                    |      |       |       |            |          |
    |   4 |     BITMAP CONVERSION FROM ROWIDS|      |       |       |            |          |
    |*  5 |      INDEX RANGE SCAN            | II   |       |       |     1   (0)| 00:00:01 |
    |   6 |     BITMAP CONVERSION FROM ROWIDS|      |       |       |            |          |
    |*  7 |      INDEX RANGE SCAN            | IU   |       |       |     1   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       5 - access("USER_ID"=58)
       7 - access("USERNAME"='EYGLE')

     and_equal, index_join, index_combine这三种都是oracle利用索引关联获得数据的方法,三者的目的都是为了最大限度的利用索引,减少回表的代价.但是三者的实现方法是有区别的,下面一一来分析.


    and_equal
    这种方式需要查询条件里面包括所有索引列,然后取得每个索引中得到的rowid列表,然后对这些列表做merge join,过滤出相同的rowid后再去表中获取数据或者直接从索引中获得数据.and_equal有一些限制,比如它只对单列索引有效,只对非唯一索引 有效,使用到的索引不能超过5个,查询条件只能是”=”.在10g中,and_equal已经被废弃了,只能通过hint才能生效.

    create table test as select * from dba_objects;

    create index ind_test_owner on test(owner);

    create index ind_test_object_name on test(object_name);

    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    ——————————————————————————-
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ——————————————————————————-
    | 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
    |* 1 | AND-EQUAL | | | | |
    |* 2 | INDEX RANGE SCAN| IND_TEST_OWNER | 1 | | 1 (0)|
    |* 3 | INDEX RANGE SCAN| IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
    ——————————————————————————-

    如果查询条件只包含owner

    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’;

    Execution Plan
    ———————————————————-

    ———————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
    | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 29 | 2 (0)|
    |* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
    ———————————————————————————–

    修改owner,object_name为非空

    alter table test modify(owner not null);
    alter table test modify(object_name not null);

    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’;

    Execution Plan
    ———————————————————-

    ———————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
    | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 29 | 2 (0)|
    |* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
    ———————————————————————————–

    效果一样

    查询条件是”>”的情况

    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where owner>’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    —————————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    —————————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
    |* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
    |* 2 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
    —————————————————————————————–

    查询条件是in的情况
    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where owner in(’test’,'dba’) and object_name=’test’;

    Execution Plan
    ———————————————————-

    —————————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    —————————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
    |* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
    |* 2 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
    —————————————————————————————–

    再来看一下回表的情况

    SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    —————————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    —————————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
    |* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
    | 2 | AND-EQUAL | | | | |
    |* 3 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
    |* 4 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
    —————————————————————————————–

    先通过and_equal取得rowid列表,然后从表中返回数据.

    index_join
    index join顾名思义是对index进行关联,oracle通过hash index join的方式实现了避免对表的访问.所有的数据都从索引中直接获得.它不受查询条件影响,可以是唯一索引,也可以是多列索引.

    SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    ——————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ——————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 29 | 3 (34)|
    |* 1 | VIEW | index$_join$_001 | 1 | 29 | 3 (34)|
    |* 2 | HASH JOIN | | | | |
    |* 3 | INDEX RANGE SCAN| IND_TEST_OWNER | 1 | 29 | 1 (0)|
    |* 4 | INDEX RANGE SCAN| IND_TEST_OBJECT_NAME | 1 | 29 | 1 (0)|
    ——————————————————————————–

    可以不带查询条件,只不过由index range scan变成了index fast full scan

    SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name from test
    2 ;

    Execution Plan
    ———————————————————-

    ————————————————————————————
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ————————————————————————————

    | 0 | SELECT STATEMENT | | 51984 | 1472K| 478 (2)|
    | 1 | VIEW | index$_join$_001 | 51984 | 1472K| 478 (2)|
    |* 2 | HASH JOIN | | | | |
    | 3 | INDEX FAST FULL SCAN| IND_TEST_OWNER | 51984 | 1472K| 153 (2)|
    | 4 | INDEX FAST FULL SCAN| IND_TEST_OBJECT_NAME | 51984 | 1472K| 322 (1)|
    ————————————————————————————

    如果不是所有数据都能从索引获得,那么将不会使用index join

    SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    ———————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————–

    | 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
    |* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
    |* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
    ———————————————————————————–

    index_combine
    index combine最早是用在bitmap index上的,在9i开始oracle默认可以使用在btree索引上,这是由_b_tree_bitmap_plans参数来控制的.oracle将 btree索引中获得的rowid信息通过BITMAP CONVERSION FROM ROWIDS的步骤转换成bitmap进行匹配,然后匹配完成后通过BITMAP CONVERSION TO ROWIDS再转换出rowid获得数据或者回表获得数据.

    SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    ———————————————————————————————
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————————

    | 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
    | 1 | BITMAP CONVERSION TO ROWIDS | | 1 | 29 | 2 (0)|
    | 2 | BITMAP AND | | | | |
    | 3 | BITMAP CONVERSION FROM ROWIDS| | | | |
    |* 4 | INDEX RANGE SCAN | IND_TEST_OWNER | | | 1 (0)|
    | 5 | BITMAP CONVERSION FROM ROWIDS| | | | |
    |* 6 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | | | 1 (0)|
    ———————————————————————————————

    回表取数据的情况

    SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

    Execution Plan
    ———————————————————-

    ———————————————————————————————-
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————————-
    | 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
    | 1 | TABLE ACCESS BY INDEX ROWID | TEST | 1 | 40 | 2 (0)|
    | 2 | BITMAP CONVERSION TO ROWIDS | | | | |
    | 3 | BITMAP AND | | | | |
    | 4 | BITMAP CONVERSION FROM ROWIDS| | | | |
    |* 5 | INDEX RANGE SCAN | IND_TEST_OWNER | | | 1 (0)|
    | 6 | BITMAP CONVERSION FROM ROWIDS| | | | |
    |* 7 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | | | 1 (0)|
    ———————————————————————————————-

    不带查询条件的情况,index combine将不被使用

    SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name from test
    2 ;

    Execution Plan
    ———————————————————-

    ———————————————————————————–
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
    ———————————————————————————–

    | 0 | SELECT STATEMENT | | 51984 | 1472K| 1480 (1)|
    | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 51984 | 1472K| 1480 (1)|
    | 2 | INDEX FULL SCAN | IND_TEST_OWNER | 51984 | | 123 (2)|
    ———————————————————————————–

    index_combine会是and_equal的很好的替代者,随着and_equal的退出,index_combine将更多得被我们看到.

     

    测试 

    CREATE TABLE SYSTEM.TEST

    (

      A  INTEGER,

      B  INTEGER,

      C  VARCHAR2(1000 BYTE)

    );

    CREATE INDEX SYSTEM.TEST_IDX1 ON SYSTEM.TEST (A);

    CREATE INDEX SYSTEM.TEST_IDX2 ON SYSTEM.TEST (B);

     

     

    insert into test values(1,2,'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgababcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg');

    insert into test values(1,3,'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgaabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgbcdefgabcdefgabcdefg');

    insert into test values(4,2,'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgdefgabcdefg');

    insert into test values(11,11,'abcdefgabcdefgabcabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg');

     

    insert into test select * from test where a=1 and b=3;

    commit;

    --3 000 rows  

     

    insert into test select * from test where a=4 and b=2;

    commit;

    --6 0000 rows

     

    insert into test select * from test where a=11 and b=11;

    commit;

    --100W,多插數據可以比較出執行時間

     

    select * from test where a=1 and b=2 –-只有一條記錄的結果集

     

    分析前會走and_equal(

     

    analyze index test_idx1 compute statistics;

    analyze index test_idx2 compute statistics;

    analyze table test compute statistics;

     

    分析後比較一下它們的cost及執行效率

     

    select * from test where a=1 and b=2

     

    select /*+ index(test test_idx1) */ * from test where a=1 and b=2

     

    select /*+ and_equal(test test_idx1 test_idx2) */ * from test where a=1 and b=2

     

    select /*+ index_combine(test test_idx1 test_idx2) */ * from test where a=1 and b=2

      

    不同的環境,index_combine與and_equal的效率應該還是有些差異,因為其中有一個bitmap convert的過程

  • 相关阅读:
    利用 windbg 脚本动态调试代码
    GetHotkeys 通过驱动获取系统热键 [ 顺便写了 SSDT + Shadow SSDT ]
    获取系统热键链表windbg脚本 GetHotkeys windbg script
    利用SetSysColor函数实现主题修改
    Javascript文件夹选择框的两种解决方案
    Javascript使用AjaxPro构建自动补全,同时自动生成待输行【原创】
    在UpdatePanel中弹出对话框
    JS动态创建表格比较【转】
    JS精美日历时间控件
    myeclipse快捷键大全【转】
  • 原文地址:https://www.cnblogs.com/pugang/p/13649912.html
Copyright © 2011-2022 走看看