• Full scan vs index 执行计划的实验


    根据Oracle-L邮件列表里主题「

    Full scan vs index

    」的讨论而来。
    1、测试环境创建
    SYS@HEMESRHTDB2(1.206)> select * from v$version;
    BANNER
    --------------------------------------------------------------------------------
    Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
    PL/SQL Release 11.2.0.3.0 - Production
    CORE11.2.0.3.0Production
    TNS for Linux: Version 11.2.0.3.0 - Production
    NLSRTL Version 11.2.0.3.0 - Production
     
    SYS@HEMESRHTDB2(1.206)> 
    create table t2
        as
        with generator as (
         select --+ materialize
           rownum pk
           from all_objects
           where rownum<=4000
           )
        select
           /*+ ordered use_nl(v2)*/
         rownum pk,
         round(dbms_random.value(1,2)) a,
         round(dbms_random.value(1,5)) b,
         round(dbms_random.value(1,10)) c,
         round(dbms_random.value(1,100)) d,
         round(dbms_random.value(1,1000000)) e 
       from
         generator v1,
         generator v2
       where
         rownum<=600000
         /
    Table created.
     
    SYS@HEMESRHTDB2(1.206)> select * from t2 where rownum<=100;
     
    PK    A       B  C     DE
    ---------- ---------- ---------- ---------- ---------- ----------
    1    2       1  3    80   296354
    2    2       3  9    47   531531
    3    2       3  1    10   330623
    4    2       5  2    35    21138
    5    2       5  7    50   425066
    6    2       3  9    75   322065
    7    2       4  1    93    55360
    8    2       1  8    99   378844
    9    2       5  8    72   869863
    10    2       5  2    63   373369
    11    1       4  4    37   313221
    12    1       5  8    68    40918
    13    1       2  8    48   457786
    14    2       3  2    83   316507
    15    1       4  2    14   734118
    16    1       4  7    59    47266
    ……
    ……
     
    SYS@HEMESRHTDB2(1.206)> create index ix_t2_key on t2(PK,A) online nologging;
    Index created.
    SYS@HEMESRHTDB2(1.206)> create index ix_t2_D on t2(D) online nologging;
    Index created.
    SYS@HEMESRHTDB2(1.206)> alter session set statistics_level ='ALL' ; 
    Session altered.
     
    2、测试4种情况
    索引情况。
    ix_t2_key on t2(PK,A) 
    ix_t2_D   on t2(D)
     
    Select count(*) from T2 where pk > 520000;
    select count(*) from t2 where A=1;
    Select count(D) from T2 where pk > 520000;
    3、测试
    实验1
    SYS@HEMESRHTDB2(1.206)> select count(*) from T2 where pk > 520000;
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
     
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID9c98xbdbfww9r, child number 0
    -------------------------------------
    Select count(*) from T2 where pk > 520000
     
    Plan hash value: 2050414396
     
     
    实验2
    SYS@HEMESRHTDB2(1.206)> select count(*) from t2 where A=1;
     
      COUNT(*)
    ----------
        299737
     
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
     
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID651cjf8pmhb51, child number 0
    -------------------------------------
    select count(*) from t2 where A=1
     
    Plan hash value: 2933116225
    实验3
    SYS@HEMESRHTDB2(1.206)> select count(D) from t2 where pk>=520000; 
     
      COUNT(D)
    ----------
         80001
     
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
     
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID41uuvuyutgn6q, child number 0
    -------------------------------------
    select count(D) from t2 where pk>=520000
     
    Plan hash value: 3321871023
    4、结论和延伸
    实验1
    SYS@HEMESRHTDB2(1.206)> select count(*) from T2 where pk > 520000;
    按照预期走索引IX_T2_KEY。
    实验2
    SYS@HEMESRHTDB2(1.206)> select count(*) from t2 where A=1;
    也同预期。
    实验3
    SYS@HEMESRHTDB2(1.206)> select count(D) from t2 where pk>=520000; 
    为啥变成count(D)就完全不一样了?
     
    我们加上index hint看看效果如何?
     
    延伸实验 Index hint
    SYS@HEMESRHTDB2(1.206)> select /*+ index(T2 IX_T2_KEY) */ count(D) from t2 where pk>=520000; 
     
      COUNT(D)
    ----------
         80001
     
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
     
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID4s4zzmrzdzrbt, child number 0
    -------------------------------------
    select /*+ index(T2 IX_T2_KEY) */ count(D) from t2 where pk>=520000
     
    Plan hash value: 948933721
     
     
    这儿看起来好像有些眉目了,Cost虽然比全表扫描的要大,但真正耗用的buffers根本就不大。
    问题出在统计信息!!?
     
    SYS@HEMESRHTDB2(1.206)> 
     
    select
      column_name,
      num_distinct,
      histogram, num_buckets,
      to_char(LAST_ANALYZED, 'yyyy-mm-dd hh24:mi:ss') 
    from all_tab_col_statistics 
      where upper(table_name)='T2';
     
    no rows selected
     
    果然咧,这时收集下统计信息。
     
    SYS@HEMESRHTDB2(1.206)> 
    begin
      dbms_stats.gather_table_stats(
      ownname => user,
      tabname => 'T2',
      estimate_percent =>100,
      cascade => true);
    end;
    /
    PL/SQL procedure successfully completed.
     
    「for all columns 或者 「for all indexed columns」都OK,重要的是覆盖count(D) 字段,CBO才能够计算出正确的cost。
    可以加个/*1*/之类的使执行计划重新解析,或是alter system flush shared_pool; 
    嗯,随你喜欢。
     
    SYS@HEMESRHTDB2(1.206)> select /*1*/ count(D) from t2 where pk>=520000;
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID6z1bc6xv0anrn, child number 0
    -------------------------------------
    select /*1*/ count(D) from t2 where pk>=520000
     
    Plan hash value: 948933721
     
    这个时候,便会选择正确的索引了,
    当然,你也可以把D字段包含入索引IX_T2_KEY中。
     
    最后:
     
    如果扫描的范围再一些?会发生什么?
    10万/60万
     
    SYS@HEMESRHTDB2(1.206)> select /*2*/ count(D) from t2 where pk>=500000; 
     
      COUNT(D)
    ----------
        100001
     
    SYS@HEMESRHTDB2(1.206)> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'allstats last ADVANCED PEEKED_BINDS')); 
     
    PLAN_TABLE_OUTPUT
    -------------------------------------
    SQL_ID7shudyqdb5nbk, child number 0
    -------------------------------------
    select /*2*/ count(D) from t2 where pk>=500000
     
    Plan hash value: 3321871023
     
     
  • 相关阅读:
    非域账户如何连接SQL Server Analysis Service
    Ranet.UILibrary.OLAP
    给Silverlight项目Ranet.UILibrary.OLAP添加客户端调试功能
    编译及安装QCA类库
    关于软件生态环境
    Windows7中操作mysql数据库
    介绍自己
    VS2008技巧收集
    .NET开发不可错过的25款必备工具
    如何做搜索引擎优化(SEO)
  • 原文地址:https://www.cnblogs.com/dap570/p/3396513.html
Copyright © 2020-2023  润新知