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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM