• 01-oracle分区转换导致索引失效的问题


    一、总结

    1、背景

    将一个临时表的数据通过分区转换到一个分区表的新分区的时候,导致数据库查询的时候走了全部扫描,即使是查旧分区里的数据,也是走的全表扫面;

    2、通过测试,做完分区转换后,最好rebuild一下索引,不然执行计划会出错,如果数据量大的话,是致命的问题;

    3、解决办法

         给临时表创建索引,分区转换的时候添加including indexes,转换之后的索引就不会失效,详细测试步骤见第三部分;

    二、模拟演示

    1、创建分区表

    create table student (
    id int,
    name varchar2(20),
    datet varchar2(20)
    )
    partition by range(datet)
    (
    partition p01 values less than('20200802'),
    partition p02 values less than('20200803'),
    partition p03 values less than('20200804')
    )

    2、创建本地索引

    create index ind_date on student(datet) local;

    3、插入数据

    insert into student values(1,'jack','20200801');
    insert into student values(2,'rose','20200802');
    insert into student values(3,'ksk','20200801');
    insert into student values(4,'wade','20200803');
    insert into student values(5,'sjkj','20200801');
    insert into student values(6,'dskj','20200803');
    insert into student values(7,'dsku','20200802');
    insert into student values(8,'dsuk','20200801');

    4、查看分区索引的状态

    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_DATE'

     注:可以看到3个分区的状态都是USABLE

    select index_name,partition_name,status from user_ind_partitions where index_name='IND_DATE'

    5、创建一张临时表并插入数据

    --创建临时表,字段要和分区表的一致
    create table student_tmp (
    id int,
    name varchar2(20),
    datet varchar2(20)
    )
    
    --插入数据
    insert into student_tmp values(20,'dsakdjfgfg','20200804');
    insert into student_tmp values(21,'dsakdj','20200804');
    insert into student_tmp values(22,'dssdgfdj','20200804');
    insert into student_tmp values(23,'dsakdjllgf','20200804');

    6、给分区表student添加一个新分区(后面要把临时表的数据插入到该新分区)

    --添加新分区
    alter table student add partition p04 values less than('20200805')
    
    --查看表的所有分区
    select partition_name from user_tab_partitions where table_name='STUDENT';
    
    --查看分区的状态
    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_DATE'

     

     注:这个时候可以看到4个分区的状态都是USABLE

    7.分区转换(把临时表的数据转换到分区表的新分区)

    alter table student exchange partition p04 with table student_tmp;

    8、查看临时表的数据(已经为空)

    select * from student_tmp

    9、查看分区表新分区的数据

    select * from student partition(p04)

    10、查看分区表的新分区索引是否失效

    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_DATE'

     注:可以看到新分区的索引是失效的

    11、查询新分区的数据,看执行计划是否走索引

    set autotrace on
    select * from student where id =20;

    注:可以看到查询新分区里的数据,走的是全表扫描 

    12、查看不在新分区的数据,看执行计划是否走索引

    set autotrace on
    select * from student where id =1; 

     注:看结果,即使是不在新分区里的数据,走的也是全表扫描

    三、解决办法

    1、创建分区表people

    create table people
    (
    id number,
    name varchar2(20),
    time date
    )
    partition by range (time)
    (
    partition p01 values less than (to_date('20200102 00:00:00','yyyymmdd hh24:mi:ss')),
    partition p02 values less than (to_date('20200103 00:00:00','yyyymmdd hh24:mi:ss')),
    partition p03 values less than (to_date('20200104 00:00:00','yyyymmdd hh24:mi:ss'))
    )

    2、创建本地索引

    create index ind_p_id on people(id) local;

    3、插入数据

    --p01
    declare
    i number;
    begin 
      for i in 1..20 loop
      insert into people values(i,'ms',to_date('20200101 12:00:00','yyyymmdd hh24:mi:ss'));
    end loop;
    end;
    
    --p02
    declare
    i number;
    begin 
      for i in 21..50 loop
      insert into people values(i,'ms',to_date('20200102 12:00:00','yyyymmdd hh24:mi:ss'));
    end loop;
    end;
    
    --p03
    declare
    i number;
    begin 
      for i in 51..100 loop
      insert into people values(i,'ms',to_date('20200103 12:00:00','yyyymmdd hh24:mi:ss'));
    end loop;
    end;
    
    --查看个分区的数据
    select * from people  partition(p01)
    select * from people  partition(p02)
    select * from people  partition(p03)

    4、查看分区索引的状态

    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_P_ID'
    
    select index_name,partition_name,status,tablespace_name 
    from user_ind_partitions where index_name='IND_P_ID'

    5、查看一条数据,看是否走索引

    set linesize  200
    set pagesize 1000
    set autotrace on
    select * from people where id=23;

    6、创建一张临时表并创建索引、插入数据

    create table people_tmp
    (
    id number,
    name varchar2(20),
    time date
    )
    --创建索引
    create index ind_ptmp_id on people_tmp(id) ;
    
    --插入数据
    declare
    i number;
    begin 
      for i in 101..150 loop
      insert into people_tmp values(i,'ms',to_date('20200104 12:00:00','yyyymmdd hh24:mi:ss'));
    end loop;
    end;
    
    --查看临时表数据
    select * from people_tmp

    7、给分区表peopel添加一个新分区(后面要把临时表的数据插入到该新分区)

    --添加新分区p04
    alter table people add partition p04
    values less than (to_date('20200105 00:00:00','yyyymmdd hh24:mi:ss'));
    
    --查看分区索引状态
    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_P_ID'

    8、分区转换(使用including indexes的方式把临时表的数据转换到分区表的新分区)

    --分区转换
    alter table people exchange partition p04 with table people_tmp including indexes;
    
    --查看分区索引状态
    select index_owner,index_name,partition_name,status,tablespace_name 
    from dba_ind_partitions where index_name='IND_P_ID'

     注:可以看到装换前后,分区索引都是有效的

    9、查看新分区的数据

    10、查询新分区的数据,看执行计划是否走索引

    set linesize  200
    set pagesize 1000
    set autotrace on
    select * from people where id=105;

  • 相关阅读:
    大数据基本概念及Hadoop技术基础
    基于 ReliefF和K-means算法的应用
    利用Hadoop和Spark处理用户心跳周期数据
    Java线程池源码解析及高质量代码案例
    muleESB的第一个开发实例-HelloWorld(二)
    [USACO11JAN]道路和飞机Roads and Planes
    CH6101 最优贸易
    POJ3662 Telephone Lines
    扫描线+线段树例题(HDU1542)
    关于Dinic算法的几点讨论
  • 原文地址:https://www.cnblogs.com/jialanyu/p/13477218.html
Copyright © 2020-2023  润新知