• oracle中直方图的使用


    本文从不绑定变量和绑定变量两种情况讨论直方图的作用

    一、不绑定变量

    SQL> create table test(name varchar2(10));
    表已创建。
    SQL> insert into test select 'A' from table1;
    已创建25064行。
    SQL> insert into test values('B');
    已创建 1 行。

    SQL> insert into test values('C');
    已创建 1 行。

    SQL> select name,count(1) from test group by name;
    NAME         COUNT(1)
    ---------- ----------
    A               25064
    B                   1
    C                   1

    SQL> create index i_test on test(name);
    索引已创建。

    SQL> analyze table test compute statistics;
    表已分析。

    SQL> select * from test where name='A';
    已选择25064行。

    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"='A')


    统计信息
    ----------------------------------------------------------
             32  recursive calls
              0  db block gets
           1720  consistent gets
              0  physical reads
              0  redo size
         337843  bytes sent via SQL*Net to client
          18770  bytes received via SQL*Net from client
           1672  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          25064  rows processed

    SQL> select * from test where name='B';


    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"='B')

    统计信息
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
             47  consistent gets
              0  physical reads
              0  redo size
            407  bytes sent via SQL*Net to client
            400  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed

    只需返回一条数据,但做了全表扫描。

    因为,oracle只知道name列有3个不同的值,但不知道每个不同的值分别有多少记录,oracle默认这些数据是完全均匀的,

    所以,当用name做条件时,oracle认为会返回总记录的三分之一(从Rows=8355可以看出)

    对test表生成直方图后再做同样的查询

    SQL> analyze table test compute statistics for table for all indexes for all indexed columns;

    表已分析。

    SQL> select * from test where name='A';
    已选择25064行。

    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      | 25064 | 25064 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST | 25064 | 25064 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"='A')

    统计信息
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
           1717  consistent gets
              0  physical reads
              0  redo size
         337843  bytes sent via SQL*Net to client
          18770  bytes received via SQL*Net from client
           1672  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          25064  rows processed

    SQL> select * from test where name='B';


    执行计划
    ----------------------------------------------------------
    Plan hash value: 3559141341
    ---------------------------------------------------------------------------
    | Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------
    |   0 | SELECT STATEMENT |        |     1 |     1 |     1   (0)| 00:00:01 |
    |*  1 |  INDEX RANGE SCAN| I_TEST |     1 |     1 |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - access("NAME"='B')


    统计信息
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              3  consistent gets
              0  physical reads
              0  redo size
            407  bytes sent via SQL*Net to client
            400  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed

    可见,生成了直方图后,oracle会根据数据的实际分布情况选择合适的执行计划。

    ###############################################################

    二、绑定变量的情况下

    SQL> analyze table test compute statistics;
    表已分析。

    SQL> var o varchar2(10)
    SQL> exec :o:='A'
    PL/SQL 过程已成功完成。

    SQL> select * from test where name=:o;
    已选择25064行。

    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"=:O)


    统计信息
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
           1717  consistent gets
              0  physical reads
              0  redo size
         337843  bytes sent via SQL*Net to client
          18770  bytes received via SQL*Net from client
           1672  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          25064  rows processed

    SQL> exec :o:='B'
    PL/SQL 过程已成功完成。

    SQL> select * from test where name=:o;

    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"=:O)

    统计信息
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
             47  consistent gets
              0  physical reads
              0  redo size
            407  bytes sent via SQL*Net to client
            400  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed

    从以上测试可以看出,在绑定变量的情况下,如果没有分析直方图,两个查询都使用了相同的执行计划——全表扫描。

    在第一次解析SQL的时候,因为oracle不知道数据的具体分布,所以它认为会返回三分之一的数据,所以选择了全表扫描。

    在以后执行同样的SQL时会重用该SQL,都会使用第一次解析生成的执行计划。

    在本例中,无论:o是'A'还是'B',都会使用全表扫描,那么,我们是否可以得出这样一个结论:

    如果分析了直方图,那么如果第一次硬解析SQL时:o是'A'时,会使用全表扫描;:o是'B'时,会使用索引扫描呢?看如下的测试:

    SQL> alter system flush shared_pool;
    系统已更改。
    SQL> analyze table test delete statistics;
    表已分析。
    SQL> analyze table test compute statistics for table for all indexes for all indexed columns;
    表已分析。
    SQL> exec :o:='A'
    PL/SQL 过程已成功完成。
    SQL> select * from test where name=:o;
    已选择25064行。

    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"=:O)

    统计信息
    ----------------------------------------------------------
             32  recursive calls
              0  db block gets
           1720  consistent gets
              0  physical reads
              0  redo size
         337843  bytes sent via SQL*Net to client
          18770  bytes received via SQL*Net from client
           1672  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          25064  rows processed

    SQL> alter system flush shared_pool;
    系统已更改。
    SQL> analyze table test delete statistics;
    表已分析。
    SQL> analyze table test compute statistics for table for all indexes for all indexed columns;
    表已分析。
    SQL> exec :o:='B'
    PL/SQL 过程已成功完成。

    SQL> select * from test where name=:o;


    执行计划
    ----------------------------------------------------------
    Plan hash value: 1357081020
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |  8355 |  8355 |    14   (8)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| TEST |  8355 |  8355 |    14   (8)| 00:00:01 |
    --------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter("NAME"=:O)

    统计信息
    ----------------------------------------------------------
             32  recursive calls
              0  db block gets
              6  consistent gets
              0  physical reads
              0  redo size
            407  bytes sent via SQL*Net to client
            400  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed

    从这个结果可以看出,分析了直方图后,无论:o的值是'A'还是'B',第一次执行该sql时,使用的都是全表扫描,这与刚才的推论不一致了。

    如果真是这样的话,使用绑定变量对表做直方图还有什么意义呢?其实这应该算是oracl的一个bug,在这里autotrace的结果是不对的,我们可以用10046看

    启用 Oracle 10046 调试事件

    SQL> alter system flush shared_pool;
    SQL> analyze table test delete statistics;
    SQL> analyze table test compute statistics for table for all indexes for all indexed columns;
    SQL> exec :o:='A'

    SQL> ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';

    SQL> select * from test where name=:o;

    SQL> ALTER SESSION SET EVENTS '10046 trace name context off';

    将C:oracleproduct10.2.0adminorcludump下的最新trc文件copy至桌面

    C:UsersLEEDesktop> tkprof orcl_ora_4516.trc orcla.sql

    查看orcla.sql

    select * 
    from
     test where name=:o

    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        2      0.04       0.11          0          3          0           0
    Execute      2      0.00       0.02          0          0          0           0
    Fetch     1674      0.14       0.14          0       1720          0       25065
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total     1678      0.18       0.28          0       1723          0       25065

    Misses in library cache during parse: 2
    Optimizer mode: ALL_ROWS
    Parsing user id: 58  

    Rows     Row Source Operation
    -------  ---------------------------------------------------
      25064  TABLE ACCESS FULL TEST (cr=1717 pr=0 pw=0 time=100367 us)

    ——————————————————

    SQL> alter system flush shared_pool;
    SQL> analyze table test delete statistics;
    SQL> analyze table test compute statistics for table for all indexes for all indexed columns;
    SQL> exec :o:='B'

    SQL> ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';

    SQL> select * from test where name=:o;

    SQL> ALTER SESSION SET EVENTS '10046 trace name context off';

    将C:oracleproduct10.2.0adminorcludump下的最新trc文件copy至桌面

    C:UsersLEEDesktop> tkprof orcl_ora_4516.trc orclb.sql

    查看orclb.sql

    select * 
    from
     test where name=:o

    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.04          0          0          0           0
    Execute      1      0.00       0.01          0          0          0           0
    Fetch        2      0.00       0.00          0          3          0           1
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total        4      0.00       0.05          0          3          0           1

    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 58  

    Rows     Row Source Operation
    -------  ---------------------------------------------------
          1  INDEX RANGE SCAN I_TEST (cr=3 pr=0 pw=0 time=51 us)(object id 57877)

    到此为止可以可以得出如下结论:
    1、无论是否绑定变量,对数据分布不均的情况下柱状图都是很有效的。假如数据是均衡的,没有必要使用直方图。
    2、对数据分布不均匀的情况下,使用绑定变量可能会造成恶果,就算对表做了柱状图也一样
    3、使用绑定变量,sql第一次执行决定了以后同样的sql执行的执行计划
    4、AUTOTRACE的信息不一定准确,必要时要用10046查看需要的信息

    本文转自:http://blog.csdn.net/narutobing/article/details/7881082

  • 相关阅读:
    postgresql清理工具
    Vue 创建项目
    Vue3 项目打包
    Oracle Linux7 与Oracle Linux8 下载rpm包的位置
    PostgreSQL 关闭session链接,删除数据库方法(转载)
    浅析状态机模式的理解以及如何使用状态机模式简化代码里复杂的 if else 逻辑
    浅析黑盒/白盒测试用例的基本设计方法:等价类划分法、临界值分析法、错误推测法、因果图法
    浅析设计测试用例的四条原则:单个用例覆盖最小化原则、测试用例替代产品文档功能原则、单次投入成本和多次投入成本原则、使测试结果分析和调试最简单化原则
    浅析软件测试中的一些常见理论:杀虫剂效应、金字塔模型、缺陷集群性原则、软件测试活动依赖于软件测试背景、软件测试的7大基本原则
    golang var xx struct定义struct类型变量?
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/4812822.html
Copyright © 2020-2023  润新知