zoukankan      html  css  js  c++  java
  • oracle表分析 示例

    drop table test;

    select count(*) from test;
    --创建测试表
    create table test
    (
    id number(9),
    nick varchar2(30)
    );

    --插入测试数据
    begin
      for i in 1..100000 loop
            insert into test(id) values(i);
      end loop;
      commit;
    end;

    select * from test;

    --更新nick字段,使数据发生严重倾斜
    update test set nick='abc' where rownum<99999;

    --创建索引
    create index idx_test_nick on test(nick);

    update test set nick='def' where nick is null;

    --只对索引进行分析
    analyze index idx_test_nick compute statistics;

    select * from user_indexes;
    --查看索引名,对应存储的数据块,不同的key数量,记录数(行数)的分析信息
    select index_name, LEAF_BLOCKS, DISTINCT_KEYS, NUM_ROWS
      from user_indexes
     where index_name = 'IDX_TEST_NICK';

    --dba_tab_col_statistics

    --查看表的统计信息
    select COLUMN_NAME, NUM_BUCKETS, num_distinct
      from USER_tab_columns
     where table_name = 'TEST';

    select * from test where nick ='abc';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE)

    select * from test where nick ='def';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE)
    --由上可以看到,对索引分析之后,sql的执行路径都是基于规则的,索引的字段的偏移
    --先根据索引找到rowid,然后再根据rowid读取记录,这个过程肯定比全表扫描读取记录要慢

    --user_part_col_statistics  分区分析信息

    --分析表的第二列nick
    analyze table test compute statistics for columns size 2 nick;

    select * from test where nick ='abc';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST'
       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE)
    --根据上面的执行计划,还是按照规则来执行的

    --分析表
    analyze table test compute statistics for table;

    select * from test where nick ='abc';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=49 Card=99998 Bytes=
              1499970)

       1    0   TABLE ACCESS (FULL) OF 'TEST' (Cost=49 Card=99998 Bytes=14
              99970)
    --分析表之后,完全按照成本来执行

    --删除所有的统计数据,并只对表与列进行分析,不分析索引,
    --ORACLE使用CBO的优化器,并产生了正确的执行计划
    analyze table test delete statistics;


    --分析列nick
    analyze table test compute statistics for table for columns size 2 nick;

    select * from test where nick ='abc';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=49 Card=99998 Bytes=
              1499970)

       1    0   TABLE ACCESS (FULL) OF 'TEST' (Cost=49 Card=99998 Bytes=14
              99970)
      
    --
    select * from test where nick ='def';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=30)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=2 Byt
              es=30)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE) (Cost
              =1 Card=2)


    --创建TEST表ID列上的索引,但不对索引进行分析
    create index idx_test_id on test(id);
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1000 Bytes=15
              000)

       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1000
              Bytes=15000)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_ID' (NON-UNIQUE) (Cost=1
               Card=400)


    --当条件中即有id,又有nick时,因为nick上有直方图,ORACLE知道nick='abc'的值特别的多,所以不走IDX_TEST_NICK索引,走IDX_TEST_ID上的索引
    select * from test where id=5 and nick='abc';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1000 Bytes=15
              000)

       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1000
              Bytes=15000)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_ID' (NON-UNIQUE) (Cost=1
               Card=400)

    --当条件中即有id,又有nick时,因为nick上有直方图,ORACLE知道nick='def'的值特别的少,所以走IDX_TEST_NICK上的索引,不走IDX_TEST_ID索引
    select * from test where id=5 and nick='def';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=15)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1 Byt
              es=15)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE) (Cost
              =1 Card=2)

    select * from test where nick='def'  and id=5;
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=15)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1 Byt
              es=15)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_NICK' (NON-UNIQUE) (Cost
              =1 Card=2)

    --在分析ID列后,ORACLE发现ID列的选择度更高,所以不再选择IDX_TEST_NICK索引,而是选择IDX_TEST_ID
    analyze table test compute statistics for columns size 1 id;
    select * from test where id=5 and nick='def';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=7)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1 Byt
              es=7)

       2    1     INDEX (RANGE SCAN) OF 'IDX_TEST_ID' (NON-UNIQUE) (Cost=1
               Card=1)
              
    /*
    下面来看另外一种情况,我们删除所有的统计数据,然后在ID列上创建唯一索引,在此条件下,
    只分析表与分析列nick,我们看到ORACLE走了正确的执行计划,
    走了UK_TEST_ID,其实从这里也给我们带来很多的启示:
    在主键与唯一键约束的列上是否需要直方图的问题?
    如果在这些列上有像这样的查询where id > 100 and id < 1000,
    我们还是需要有直方图的,但除此之外,好像真的没有直方图的必要了!
    */
    analyze table test delete statistics;   
    drop index idx_test_id;
    create unique index uk_test_id on test(id);
    --分析表的第二列nick
    analyze table test compute statistics for table for columns size 2 nick;
    select * from test where id=5 and nick='def';
    Execution Plan
    ----------------------------------------------------------
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=15)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=2 Card=1 Byt
              es=15)

       2    1     INDEX (UNIQUE SCAN) OF 'UK_TEST_ID' (UNIQUE) (Cost=1 Car
              d=100000)
             
    从以上一系列的实验可以看出,对ORACLE的优化器CBO来说,表的分析与列的分析才是最重要的,索引的分析次之。还有我们可以考虑我们的哪些列上需要直方图,对于bucket的个数问题,oracle的默认值是75个,所以根据你的应用规则,选择合适的桶数对性能也是有帮助的。因为不必要的桶的个数的大量增加,必然会带来SQL语句硬解析时产生执行计划的复杂度问题。

    完全计算法: analyze table abc compute statistics;
    抽样估算法(抽样20%): analyze table abc estimate statistics sample 20 percent

    对表作完全计算所花的时间相当于做全表扫描,抽样估算法由于采用抽样,比完全计算法的生成统计速度要快,假如不是要求要有精确数据的话,尽量采用抽样分析法。建议对表分析采用抽样估算,对索引分析可以采用完全计算。
    我们可以采用以下方法,对数据库的表和索引及簇表定期分析生成统计信息,保证应用的正常性能

    生成索引分析,表分析的sql语句:


     

  • 相关阅读:
    C# 应用程序性能监测器,很不错的工具
    C#接口(interface)与类(class)的实例互相转换深度解析
    异步与线程深度解析
    内存管理:程序是如何被优雅的装载到内存中
    MacBookM1通过DockerDesk安装MySQL8容器
    理解异步编程体系
    asp.net导入excel方法大集合
    无法激活服务,因为它不支持 ASP.NET 兼容性
    Oracle 数据库 在asp.net中 插入时间
    微软发布更新包 修复SilverLight中的6个问题
  • 原文地址:https://www.cnblogs.com/sopost/p/2190083.html
Copyright © 2011-2022 走看看