一、總結
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;