zoukankan      html  css  js  c++  java
  • 相关列问题

     先来创建一个表T

    create table t as select level as id ,level||'a' as a,level||level||'b' as b from dual connect by level<100;

    这里A列的值能够确定B列的值,

    insert into t  select * from t; 
    .............................. 一直重复插入数据

    SQL> select count(*) from t;

      COUNT(*)
    ----------
       3244032

    create index idx1 on t(a);  
    create index idx2 on t(a,b);   
      
    BEGIN
      DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'SCOTT',
                                    tabname          => 'T',
                                    estimate_percent => 100,
                                    method_opt       => 'for all columns size skewonly',
                                    no_invalidate    => FALSE,
                                    degree           => 8,
                                    cascade          => TRUE);
    END;
    /

    SQL> select * from t where a='1a' and b='11b';
    
    已选择32768行。
    
    已用时间:  00: 00: 03.98
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 2303463401
    
    ------------------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |   331 |  3972 |    84   (0)| 00:00:02 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T    |   331 |  3972 |    84   (0)| 00:00:02 |
    |*  2 |   INDEX RANGE SCAN          | IDX2 |   331 |       |     3   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("A"='1a' AND "B"='11b')
    
    
    统计信息
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
          11838  consistent gets
           7943  physical reads
              0  redo size
         441749  bytes sent via SQL*Net to client
          24424  bytes received via SQL*Net from client
           2186  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          32768  rows processed
    
    

    因为CBO不知道A与B关系,所以计算基数等于331,

    SQL> select 1/99/99*3244032 from dual; ----这个其实就是 a选择性*b选择性 =(1/99)*(1/99)

    1/99/99*3244032
    ---------------
         330.989899

    但是实际上它要返回32768条记录

    SQL> select * from t where a='1a';
    
    已选择32768行。
    
    已用时间:  00: 00: 01.38
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 1601196873
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      | 32768 |   384K|  1874   (8)| 00:00:23 |
    |*  1 |  TABLE ACCESS FULL| T    | 32768 |   384K|  1874   (8)| 00:00:23 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("A"='1a')
    
    
    统计信息
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
          10120  consistent gets
           6312  physical reads
              0  redo size
         441749  bytes sent via SQL*Net to client
          24424  bytes received via SQL*Net from client
           2186  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          32768  rows processed
    
    

    如果where条件单独是 where a='1a' CBO 就能够算对基数,它的基数是这样计算的

    SQL> select 3244032/99 from dual;

    3244032/99
    ----------
         32768 

    很显然,这个SQL select * from t where a='1a' and b='11b' 的执行计划走错了,它应该走全表扫描,但是因为计算基数错误,导致它走 IDX2这个索引

    相关列的解决办法在Oracle中有2个,一个是动态采样,另外一个就是Oracle11g,对相关列收集扩展统计

    SQL> ALTER SESSION SET optimizer_dynamic_sampling=6;
    
    会话已更改。
    
    SQL> set lines 200
    SQL> set pages 200
    SQL> set timi on
    SQL> explain plan for select * from t where a='1a' and b='11b';
    
    已解释。
    
    已用时间:  00: 00: 00.86
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------
    Plan hash value: 1601196873
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      | 32776 |   384K|  1885   (8)| 00:00:23 |
    |*  1 |  TABLE ACCESS FULL| T    | 32776 |   384K|  1885   (8)| 00:00:23 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("A"='1a' AND "B"='11b')
    
    Note
    -----
       - dynamic sampling used for this statement
    
    已选择17行。

    设置动态采样之后 Oracle评估基数就基本正确了,关于11g扩展统计这里就不做了,有兴趣的请自己做一下。

    我对相关列的建议就是,能否在程序里拼接?如果A能确定B,那么做DB 设计的时候就不要创建B列了 直接在程序里根据A列的值生成B的值 这样减少DB的存储空间。

    如果非要在DB里设置B列,写SQL的时候就不要把2个列都写进去,也就是说不要写成
    select * from t where a='1a' and b='11b';

    直接写成
    select * from t where a='1a'  或者 select * from t where b='11b'

    这样能尽量避免CBO计算基数出错,如果这个表要与多表关联,基数一旦算错,必然导致整个SQL的执行计划全部出错,从而导致SQL性能下降。

    动态采样和扩展统计虽然是解决办法,但是如果产品要考虑兼容性呢?我的产品要同时支持ORACLE,DB2,SQLSERVER,甚至以后的国产数据库达梦,他们没有动态采样怎么办。

  • 相关阅读:
    docker容器跑tomcat遇到的坑
    PCL 编程多个点云合成
    PCL 常用小知识
    PCL点云库中的坐标系(CoordinateSystem)
    Ubuntu14.04(64位)下gcc-linaro-arm-linux-gnueabihf交叉编译环境搭建
    Windows cmd 快捷操作
    #Pragma Pack与内存分配
    线段上的整数点个数
    基于PCL绘制模型并渲染
    rosbag数据记录及转换图片、视频
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330552.html
Copyright © 2011-2022 走看看