整體結構如下:
Oracle 分區表管理之組合分區(分區索引失效與性能比較)
雖然老早就使用了分區表,終於有時間寫有關分區表的內容;不是所有的場景數據量變大需要用到分區表,一般單表數據超過2g可以考慮使用分區表,有關oracle分區表,其中單個字段作為分區比較簡單,就不作說明,Oracle 11g之前只有兩種組合分區,即rangeàhash,rangeàlist;而11g之后新增四種組合分區rangeàrange,listàrange,listàhash,listàlist;當然12c自動分區更強大了,沒有分區字段的值也可以插入該表,自動建一個分區。
分區表能夠更好的進行數據的管理以及進行性能的優化(減少訪問路徑,相當於大表切成多個小表,減少IO開銷),其中分區中重點關注的是那些字段應該作為分區字段以及分區的管理以及分區索引
在建分區的時候,也可以建立聯合分區,比如:
create table range_part_mult_col_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by range (area_code,deal_date)
(
partition p_591_201901 values less than (591,TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_591_201902 values less than (591,TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_591_201903 values less than (591,TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_591_201904 values less than (591,TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_591_201905 values less than (591,TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_591_201906 values less than (591,TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_591_201907 values less than (591,TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_591_201908 values less than (591,TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_591_201909 values less than (591,TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_591_201910 values less than (591,TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_591_201911 values less than (591,TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_591_201912 values less than (591,TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_591_202001 values less than (591,TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_591_202002 values less than (591,TO_DATE('2020-03-01', 'YYYY-MM-DD')),
partition p_591_max values less than (591,maxvalue),
partition p_592_201901 values less than (592,TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_592_201902 values less than (592,TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_592_201903 values less than (592,TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_592_201904 values less than (592,TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_592_201905 values less than (592,TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_592_201906 values less than (592,TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_592_201907 values less than (592,TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_592_201908 values less than (592,TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_592_201909 values less than (592,TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_592_201910 values less than (592,TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_592_201911 values less than (592,TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_592_201912 values less than (592,TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_592_202001 values less than (592,TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_592_202002 values less than (592,TO_DATE('2020-03-01', 'YYYY-MM-DD')),
partition p_592_max values less than (592,maxvalue),
partition p_593_201901 values less than (593,TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_593_201902 values less than (593,TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_593_201903 values less than (593,TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_593_201904 values less than (593,TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_593_201905 values less than (593,TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_593_201906 values less than (593,TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_593_201907 values less than (593,TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_593_201908 values less than (593,TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_593_201909 values less than (593,TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_593_201910 values less than (593,TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_593_201911 values less than (593,TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_593_201912 values less than (593,TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_593_202001 values less than (593,TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_593_202002 values less than (593,TO_DATE('2020-03-01', 'YYYY-MM-DD')),
partition p_593_max values less than (593,maxvalue)
);
還有就是可以簡化建分區的語句(TEMPLATE關鍵字,不過每個主分區只有子分區的這些字段,使用有很大的局限性):
create table range_list_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_201910 values less than (TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_201911 values less than (TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_201912 values less than (TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_202001 values less than (TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_202002 values less than (TO_DATE('2020-03-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue))
;
一.組合分區管理:
truncate
新建一張表組合分區的表進行truncate 操作:
create table range_list_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT))
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_201910 values less than (TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_201911 values less than (TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_201912 values less than (TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_202001 values less than (TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_202002 values less than (TO_DATE('2020-03-01', 'YYYY-MM-DD'))
);
--數據的插入
insert into range_list_part_tab(id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
比如我現在需要清理2019年一月分的數據(truncate)操作。
1) 可以逐個清理子分區表
查看主分區包含的子分區
SELECT subpartition_name FROM USER_TAB_SUBPARTITIONS WHERE partition_name='P_201901' GROUP BY subpartition_name;
select count(*) from range_list_part_tab partition(P_201901);
select count(*) from range_list_part_tab subpartition(P_201901_P_591);
alter table range_list_part_tab truncate SUBPARTITION P_201901_P_591;
alter table range_list_part_tab truncate SUBPARTITION P_201901_P_592;
這個操作只適合某些子分區數據操作,如果子分區數量一多就需要進行主分區操作
2) 清理分區
alter table range_list_part_tab truncate PARTITION P_201901;
drop
1) 刪除子分區
select count(*) from range_list_part_tab partition(P_201902);
SELECT subpartition_name FROM USER_TAB_SUBPARTITIONS WHERE partition_name='P_201902' GROUP BY subpartition_name;
刪除一下幾個分區:
alter table range_list_part_tab drop subpartition P_201902_P_591;
alter table range_list_part_tab drop subpartition P_201902_P_592;
alter table range_list_part_tab drop subpartition P_201902_P_593;
查看該分區數據減少了
刪除的分區進入回收站,如果回收站開着的話,如果誤刪,可以進行閃回,或者查詢插入。
SELECT * FROM DBA_RECYCLEBIN;
2) 刪除主分區
alter table range_list_part_tab drop partition P_201902;
alter table range_list_part_tab drop partition P_201902;
select count(*) from range_list_part_tab partition(P_201902);
add
如果主分區是介於最小以及最大分區之間,那么添加不了(有max的需要刪掉在添加),只能添加值大於最后一個分區的主分區以及相對應的子分區。
1) 組合分區添加主分區(添加主分區必須加至少一個子分區)
其中在以后的分區表中添加主分區和子分區,注意:添加的分區必須是表中主分區是最大的分區才能添加,而且添加主分區的時候,至少要添加一個子分區,否則后面添加不了子分區,只能算一級主分區,不能加子分區。
alter table range_list_part_tab add partition P_202003 values less than (TO_DATE(' 2020-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')) (subpartition P_202003_p_591 values (591));
也可以一部到位添加主分區和子分區。
2) 組合分區添加子分區(單獨添加子分區)
這個是單獨的添加子分區
alter table range_list_part_tab MODIFY PARTITION P_202003 add subpartition P_202003_p_592 values (592);
alter table range_list_part_tab MODIFY PARTITION P_202003 add subpartition P_202003_p_593 values (593);
這個是加主分區的時候沒有添加子分區,后面加不了子分區
split(分裂)
為啥會用到分區的分裂,大多數情況是分區數據分布的不均衡,其中一個分區數據量特別大,分區表並沒有提升性能,而需要的結果往往是只需要比較小的結果集。
1) 只有主分區的分裂
查看語法:
---分區表數值分區的SPLIT
drop table part_tab_split purge;
create table part_tab_split (id int,col2 int ,col3 int ,contents varchar2(4000))
partition by range (id)
(
partition p1 values less than (10000),
partition p2 values less than (20000),
partition p_max values less than (maxvalue)
)
;
insert into part_tab_split select rownum ,rownum+1,rownum+2,rpad('*',400,'*') from dual connect by rownum <=90000;
commit;
select partition_name, segment_type, bytes
from user_segments
where segment_name ='PART_TAB_SPLIT';
此種情況在某些場景中,需要p_max 分區進行分裂成多個分區,便於提升性能;
select max(id) from part_tab_split partition(p1);
select max(id) from part_tab_split partition(p2);
select max(id) from part_tab_split partition(p_max);
打算分裂成7個分區,每個分區10000值遞增。
alter table part_tab_split SPLIT PARTITION P_MAX at (30000) into (PARTITION p3 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (40000) into (PARTITION p4 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (50000) into (PARTITION p5 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (60000) into (PARTITION p6 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (70000) into (PARTITION p7 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (80000) into (PARTITION p8 ,PARTITION P_MAX);
alter table part_tab_split SPLIT PARTITION P_MAX at (90000) into (PARTITION p9 ,PARTITION P_MAX);
select max(id) from part_tab_split partition(p1);
select max(id) from part_tab_split partition(p2);
select max(id) from part_tab_split partition(p3);
select max(id) from part_tab_split partition(p4);
select max(id) from part_tab_split partition(p5);
select max(id) from part_tab_split partition(p6);
select max(id) from part_tab_split partition(p7);
select max(id) from part_tab_split partition(p8);
select max(id) from part_tab_split partition(p9);
select max(id) from part_tab_split partition(p_max);
以上是數字的,當然比較好split,如果是時間分區呢?大多數是用range時間分區
---分區表時間分區的SPLIT
drop table range_part_tab purge;
create table range_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by range (deal_date)
(
partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue)
)
;
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有15萬條,如下:
insert into range_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(591,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
insert into range_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
(sysdate+DBMS_RANDOM.VALUE(0,90)),
ceil(dbms_random.value(591,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 60000;
commit;
select count(*) from range_part_tab partition (p_201901);
select count(*) from range_part_tab partition (p_201902);
select count(*) from range_part_tab partition (p_201903);
select count(*) from range_part_tab partition (p_201904);
select count(*) from range_part_tab partition (p_201905);
select count(*) from range_part_tab partition (p_201906);
select count(*) from range_part_tab partition (p_201907);
select count(*) from range_part_tab partition (p_201908);
select count(*) from range_part_tab partition (p_201909);
select count(*) from range_part_tab partition (p_max);
很明顯最后一個分區數據量是其它分區的10倍左右。
alter table range_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (PARTITION p_201910 ,PARTITION P_MAX);
alter table range_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (PARTITION p_201911 ,PARTITION P_MAX);
alter table range_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (PARTITION p_201912 ,PARTITION P_MAX);
查看分裂后的分區值:
select count(*) from range_part_tab partition (p_201910);
select count(*) from range_part_tab partition (p_201911);
select count(*) from range_part_tab partition (p_201912);
select count(*) from range_part_tab partition (p_max);
2) 有子分區的分裂
1) 分裂只有一級分區
drop table range_list_part_tab;
create table range_list_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue));
進行數據的插入:
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有10萬條,如下:
insert into range_list_part_tab(id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
insert into range_list_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
(sysdate+DBMS_RANDOM.VALUE(0,90)),
ceil(dbms_random.value(591,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 60000;
commit;
select count(*) from range_list_part_tab partition (p_201901);
select count(*) from range_list_part_tab partition (p_201902);
select count(*) from range_list_part_tab partition (p_201903);
select count(*) from range_list_part_tab partition (p_201904);
select count(*) from range_list_part_tab partition (p_201905);
select count(*) from range_list_part_tab partition (p_201906);
select count(*) from range_list_part_tab partition (p_201907);
select count(*) from range_list_part_tab partition (p_201908);
select count(*) from range_list_part_tab partition (p_201909);
select count(*) from range_list_part_tab partition (p_max);
其中max里面么有數據:
進行分裂:
最后一個分區p_max數據相對於其他分區較大,現在需要把該分區進行分裂成多個分區(以及子分區)
語法如下:
alter table range_list_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (PARTITION p_201910 ,PARTITION P_MAX);
alter table range_list_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (PARTITION p_201911 ,PARTITION P_MAX);
alter table range_list_part_tab SPLIT PARTITION P_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (PARTITION p_201912 ,PARTITION P_MAX);
跟上面的只有主分區分裂的一樣的語法
2) 分裂主分區中的子分區
我現在新建一張表,需要分裂子分區的。
drop table list_range_part_tab purge;
create table list_range_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by list (area_code)
subpartition by range (deal_date)
(
partition p_591 values (591)
(
subpartition p591_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
subpartition p591_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
subpartition p591_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
subpartition p591_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
subpartition p591_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
subpartition p591_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
subpartition p591_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
subpartition p591_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
subpartition p591_max values less than (maxvalue)
),
partition p_592 values (592)
(
subpartition p592_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
subpartition p592_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
subpartition p592_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
subpartition p592_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
subpartition p592_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
subpartition p592_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
subpartition p592_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
subpartition p592_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
subpartition p592_max values less than (maxvalue)
),
partition p_593 values (593)
(
subpartition p593_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
subpartition p593_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
subpartition p593_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
subpartition p593_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
subpartition p593_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
subpartition p593_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
subpartition p593_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
subpartition p593_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
subpartition p593_max values less than (maxvalue)
),
partition p_594 values (594)
(
subpartition p594_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
subpartition p594_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
subpartition p594_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
subpartition p594_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
subpartition p594_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
subpartition p594_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
subpartition p594_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
subpartition p594_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
subpartition p594_max values less than (maxvalue)
),
partition p_595 values (595)
(
subpartition p595_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
subpartition p595_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
subpartition p595_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
subpartition p595_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
subpartition p595_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
subpartition p595_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
subpartition p595_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
subpartition p595_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
subpartition p595_max values less than (maxvalue)
)
);
數據插入:
insert into list_range_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,595)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
insert into list_range_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
(sysdate+DBMS_RANDOM.VALUE(0,90)),
ceil(dbms_random.value(590,595)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 60000;
commit;
查看總的分區數據以及p_max子分區數據:
SELECT 'select count(*) from LIST_RANGE_PART_TAB partition'||'('||partition_name||');' FROM USER_TAB_PARTITIONS WHERE table_name='LIST_RANGE_PART_TAB';
select count(*) from LIST_RANGE_PART_TAB partition(P_591);
select count(*) from LIST_RANGE_PART_TAB partition(P_592);
select count(*) from LIST_RANGE_PART_TAB partition(P_593);
select count(*) from LIST_RANGE_PART_TAB partition(P_594);
select count(*) from LIST_RANGE_PART_TAB partition(P_595);
P_max子分區:
SELECT 'select count(*) from LIST_RANGE_PART_TAB subpartition '||'('|| SUBPARTITION_name ||');' FROM USER_TAB_SUBPARTITIONS WHERE table_name='LIST_RANGE_PART_TAB' AND SUBPARTITION_name LIKE '%MAX%' ;
select count(*) from LIST_RANGE_PART_TAB subpartition (P591_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P592_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P593_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P594_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P595_MAX);
很明顯故意讓max子分區占整個主分區的一般數據量,現在進行max子分區的分裂
由於我設置的時間是9月份的,所以把max子分區分裂成10,11,12三個月就好了。
語句如下:
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P591_201910,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P591_201911,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P591_201912,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P592_201910,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P592_201911,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P592_201912,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P593_201910,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P593_201911,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P593_201912,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P594_201910,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P594_201911,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P594_201912,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P595_201910,subPARTITION P595_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P595_201911,subPARTITION P595_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P595_201912,subPARTITION P595_MAX);
查看分裂后的分區:
SELECT 'select count(*) from LIST_RANGE_PART_TAB subpartition '||'('|| SUBPARTITION_name ||');' FROM USER_TAB_SUBPARTITIONS
WHERE table_name='LIST_RANGE_PART_TAB' AND (SUBPARTITION_name LIKE '%MAX%' or SUBPARTITION_name LIKE '%_20191_');
select count(*) from LIST_RANGE_PART_TAB subpartition (P591_201910);
select count(*) from LIST_RANGE_PART_TAB subpartition (P591_201911);
select count(*) from LIST_RANGE_PART_TAB subpartition (P591_201912);
select count(*) from LIST_RANGE_PART_TAB subpartition (P591_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P592_201910);
select count(*) from LIST_RANGE_PART_TAB subpartition (P592_201911);
select count(*) from LIST_RANGE_PART_TAB subpartition (P592_201912);
select count(*) from LIST_RANGE_PART_TAB subpartition (P592_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P593_201910);
select count(*) from LIST_RANGE_PART_TAB subpartition (P593_201911);
select count(*) from LIST_RANGE_PART_TAB subpartition (P593_201912);
select count(*) from LIST_RANGE_PART_TAB subpartition (P593_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P594_201910);
select count(*) from LIST_RANGE_PART_TAB subpartition (P594_201911);
select count(*) from LIST_RANGE_PART_TAB subpartition (P594_201912);
select count(*) from LIST_RANGE_PART_TAB subpartition (P594_MAX);
select count(*) from LIST_RANGE_PART_TAB subpartition (P595_201910);
select count(*) from LIST_RANGE_PART_TAB subpartition (P595_201911);
select count(*) from LIST_RANGE_PART_TAB subpartition (P595_201912);
select count(*) from LIST_RANGE_PART_TAB subpartition (P595_MAX);
很明顯,分后成功,分裂后的分區每個對應相應的數據;如果一張分區表主分區和子分區都需要進行分裂,建議先主分區進行分裂,然后在對子分區進行分裂。
exchange
分區表和普通表交換
1) 有子分區的和普通表進行交換
drop table range_list_part_tab;
create table range_list_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue));
--進行數據的插入:
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有10萬條,如下:
insert into range_list_part_tab(id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
insert into range_list_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
(sysdate+DBMS_RANDOM.VALUE(0,90)),
ceil(dbms_random.value(591,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 60000;
commit;
新建一張空表,把分區表中的數據交換到該空表中:
drop table range_list_tab;
create table range_list_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
);
進行交換:
alter table range_list_part_tab exchange SUBPARTITION P_201901_P_599 with table range_list_tab including indexes update global indexes;
很明顯進行數據交換后,由於空表里面沒有數據,所以range_list_part_tab 沒有增加數據,range_list_tab數據增加了,其中,進行了數據的交換,子分區分區結構仍然還在。注意,有子分區的表不能只和普通表交換主分區(也就是必須要帶上子分區)
2) 無子分區的和普通表進行交換
重新新建表:
drop table part_tab_exch purge;
create table part_tab_exch (id int,col2 int,col3 int,contents varchar2(4000))
partition by range (id)
(
partition p1 values less than (10000),
partition p2 values less than (20000),
partition p3 values less than (30000),
partition p4 values less than (40000),
partition p5 values less than (50000),
partition p_max values less than (maxvalue)
);
insert into part_tab_exch select rownum ,rownum+1,rownum+2, rpad('*',400,'*') from dual connect by rownum <=60000;
commit;
create index idx_part_exch_col2 on part_tab_exch(col2) local;
create index idx_part_exch_col3 on part_tab_exch (col3);
drop table normal_tab purge;
create table normal_tab (id int,col2 int,col3 int,contents varchar2(4000));
create index idx_norm_col2 on normal_tab (col2);
create index idx_norm_col3 on normal_tab (col3);
--其中including indexes 可選,為了保證全局索引不要失效
alter table part_tab_exch exchange partition p1 with table normal_tab including indexes update global indexes;
同理,交換的分區表,分區結構還在,不過數據沒有了。
分區表之間的交換(分區表之間不能進行交換)
drop table range_list_subpart_tab;
create table range_list_subpart_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue));
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有10萬條,如下:
insert into range_list_subpart_tab(id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 100000;
commit;
drop table range_list_part_tab;
create table range_list_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue)
);
SELECT count(*) FROM range_list_subpart_tab SUBPARTITION (P_201901_P_599);
alter table range_list_subpart_tab exchange SUBPARTITION P_201901_P_599 with table range_list_part_tab including indexes update global indexes;
由此可出結論(被交換的表一定不能是分區表)
二.分區表索引操作失效與否
分區表有兩種索引:全局索引和本地索引(global索引和local 索引),有關全局索引和本地索引具體怎么用,以及那種更好的結合場景,下面是實驗操作。
注意:生產中或者面試的時候,如果有提到全局索引,為了讓全局索引不失效,建議加上update indexes或者update global index,
即 alter table drop/truncate/spit/merge partition_name/subpartition_name update (global) indexes;如果不加,生產上24*7業務有可能全局立馬失效,然后你就可能下崗了……
包括一些create index online/nologging 操作,最大程度的不影響DML性能;update indexes 是直接作用基表,再進行分區操作的時候 不會讓索引失效,並且DDL操作不受影響!
以下測試有的大部分不帶update global index,是為了讓實驗達到效果!!!
drop table local_part_tab;
create table local_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue));
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有100萬條,如下:
insert into local_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 1000000;
commit;
--建一個本地索引。
CREATE INDEX id_local_idx ON local_part_tab (ID) LOCAL;
--建另外一張表:
drop table global_part_tab;
create table global_part_tab (
id number,
deal_date date,
area_code number,
nbr number,
contents varchar2(4000)
)
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT)
)
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_max values less than (maxvalue));
--以下是插入2019年一整年日期隨機數和表示福建地區號含義(591到599)的隨機數記錄,共有100萬條,如下:
insert into global_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 1000000;
commit;
--建一個全局索引。
--CREATE INDEX id_global_idx ON global_part_tab (ID);
收集兩張表的統計信息。
exec dbms_stats.gather_table_stats('hr','local_part_tab');
exec dbms_stats.gather_table_stats('hr','global_part_tab');
truncate分區
查看操作local索引的狀態(注意:11.2.0.4版本sys用戶global_stats字段不能夠判斷是不是本地索引):
N/A索引分區是USABLE
還是UNUSABLE
VAILD
說明這個索引可用;
UNUSABLE
說明這個索引不可用;
USABLE
說明這個索引的分區是可用的。
select index_name, partition_name, status,global_stats
from user_ind_partitions
where index_name IN ('ID_LOCAL_IDX');
有子分區的可以查看user_IND_subPARTITIONS這個視圖:
select index_name, partition_name, status,global_stats
from user_ind_subpartitions
where index_name IN ('ID_LOCAL_IDX');
select index_name, status
from user_indexes
where index_name IN ('ID_GLOBAL_IDX');
Truncate 分區 p_201901
alter table local_part_tab truncate partition p_201901;
alter table global_part_tab truncate partition p_201901;
可以看出truncate 分區操作,本地索引仍然有效,全局索引不可用,需要重建
alter index ID_GLOBAL_IDX rebuild nologging; --nologging 線上不用記錄重做日志會快一點。
drop 分區
刪除表local_part_tab , global_part_tab 表P_MAX分區
alter table local_part_tab drop partition P_MAX;
alter table global_part_tab drop partition P_MAX;
select index_name, partition_name, status,global_stats
from user_ind_partitions
where index_name IN ('ID_LOCAL_IDX');
select index_name, status
from user_indexes
where index_name IN ('ID_GLOBAL_IDX');
可以看出drop分區操作,本地索引仍然有效,全局索引不可用,需要重建;
alter index ID_GLOBAL_IDX rebuild nologging;
add 分區
添加p_max分區
alter table local_part_tab add partition p_max values less than (maxvalue) (subpartition p591_max values (591));
alter table global_part_tab add partition p_max values less than (maxvalue) (subpartition p591_max values (591));
可以看出add分區操作,本地索引仍然有效,全局索引也可用;
split 分區
用前面的split有子分區的語句,在list_range_part_tab,id和nbr列上分別建本地和全局索引進行對比。
list_range_part_tab表進行建索引。
create index id_idx_local on list_range_part_tab(id) local;
create index nbr_idx_global on list_range_part_tab(nbr);
select index_name, partition_name, status,global_stats
from user_ind_partitions
where lower(index_name) IN ('id_idx_local');
select index_name, status
from user_indexes
where lower(index_name) IN ('nbr_idx_global');
進行分裂操作:
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P591_201910,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P591_201911,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P591_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P591_201912,subPARTITION P591_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P592_201910,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P592_201911,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P592_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P592_201912,subPARTITION P592_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P593_201910,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P593_201911,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P593_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P593_201912,subPARTITION P593_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P594_201910,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P594_201911,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P594_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P594_201912,subPARTITION P594_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2019-11-01', 'YYYY-MM-DD')) into (subpartition P595_201910,subPARTITION P595_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2019-12-01', 'YYYY-MM-DD')) into (subpartition P595_201911,subPARTITION P595_MAX);
alter table LIST_RANGE_PART_TAB split SUBPARTITION P595_MAX at (TO_DATE('2020-01-01', 'YYYY-MM-DD')) into (subpartition P595_201912,subPARTITION P595_MAX);
查看分裂后的索引:
可以看出spilt分區操作,本地索引仍然有效,全局索引不可用,需要重建;
alter index nbr_idx_global rebuild;
exchange分區
無global indexes
利用前面的exchange分區語句建表(有子分區的)part_tab_exch,normal_tab purge;以及建索引。
create index idx_part_exch_col2 on part_tab_exch(col2) local;
create index idx_part_exch_col3 on part_tab_exch (col3);
create index idx_norm_col2 on normal_tab (col2);
create index idx_norm_col3 on normal_tab (col3);
select index_name, partition_name, status,global_stats
from user_ind_partitions
where lower(index_name) IN ('idx_part_exch_col2');
select index_name, status
from user_indexes
where lower(index_name) IN ('idx_part_exch_col3','idx_norm_col2','idx_norm_col3');
USABLE表示idx_part_exch_*分區索引可用。
現在進行交換。
首先不帶上including indexes update global indexes;
alter table part_tab_exch exchange partition p1 with table normal_tab;
結論:
在分區表和普通變進行分區交換的時候,不帶上including indexes update global indexes參數,交換后,分區表交換的分區索引變成不可用(不管是本地還是全局索引),同時普通表索引也會變成不可用。需要重建全局索引,或者按照分區重建分區索引。
alter index IDX_NORM_COL2 rebuild;
alter index IDX_NORM_COL3 rebuild;
alter index IDX_PART_EXCH_COL3 rebuild;
alter index IDX_PART_EXCH_COL2 rebuild partition P1;
重建后查看:
有global indexes
刪除相應的表,重建建part_tab_exch,normal_tab purge;以及建索引。
create index idx_part_exch_col2 on part_tab_exch(col2) local;
create index idx_part_exch_col3 on part_tab_exch (col3);
create index idx_norm_col2 on normal_tab (col2);
create index idx_norm_col3 on normal_tab (col3);
part_tab_exch,normal_tab purge;以及建索引。
create index idx_part_exch_col2 on part_tab_exch(col2) local;
create index idx_part_exch_col3 on part_tab_exch (col3);
create index idx_norm_col2 on normal_tab (col2);
create index idx_norm_col3 on normal_tab (col3);
現在進行交換,帶上including indexes update global indexes;
alter table part_tab_exch exchange partition p1 with table normal_tab including indexes update global indexes;
由於分區表的全局索引和普通表碎銀類型不一樣,索引不能夠再普通表normal_tab上建idx_norm_col3索引。
drop index idx_norm_col3;
alter table part_tab_exch exchange partition p1 with table normal_tab including indexes update global indexes;
select index_name, partition_name, status,global_stats
from user_ind_partitions
where lower(index_name) IN ('idx_part_exch_col2');
select index_name, status
from user_indexes
where lower(index_name) IN ('idx_part_exch_col3','idx_norm_col2');
結論:神奇吧,除了把數據交換之外,分區表交換的分區索引也變成全局索引了。
分區表添加主鍵以及唯一鍵
--添加本地主鍵(必須包括分區字段)
alter table table_name add constraint PK_USER PRIMARY KEY(rpt_date,ID) using index local tablespace users;
--或者添加唯一索引(必須包括分區列)
CREATE UNIQUE INDEX UQ_USER ON table_name(rpt_date,ID) local tablespace users;
其中不加local 就是默認的全局主鍵或者唯一鍵了,其它語法跟普通表差距不大;索引也可以按照分區重建。
綜上結論
總結一下,先說說local索引,除了exchange交換分區的不帶上including indexes update global indexes參數時候,本地索引會變成不可用,需要重建對應的交換分區索引alter index index_name rebuild partition P1;其它情況均可用;
Global全局索引,除了add, exchange交換分區的帶上including indexes update global indexes參數時候有效,其它操作均會失效(drop,truncate,split,exchange不帶including indexes update global indexes)。
三.分區表local與全局索引之性能比較
既然存在local與global索引,存在即是合理,那什么時候我們應該再那些場景中使用這兩種索引呢?
新建兩種表:
drop table local_part_tab purge;
create table local_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT))
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_201910 values less than (TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_201911 values less than (TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_201912 values less than (TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_202001 values less than (TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_202002 values less than (TO_DATE('2020-03-01', 'YYYY-MM-DD'))
);
--數據的插入
insert into local_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 1000000;
commit;
--在local_part_tab表建本地索引:
create index id_idx_local on local_part_tab(id) local;
--建另外一張表:
drop table global_part_tab purge;
create table global_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000))
partition by range (deal_date)
subpartition by list (area_code)
subpartition TEMPLATE
(subpartition p_591 values (591),
subpartition p_592 values (592),
subpartition p_593 values (593),
subpartition p_594 values (594),
subpartition p_595 values (595),
subpartition p_596 values (596),
subpartition p_597 values (597),
subpartition p_598 values (598),
subpartition p_599 values (599),
subpartition p_other values (DEFAULT))
( partition p_201901 values less than (TO_DATE('2019-02-01', 'YYYY-MM-DD')),
partition p_201902 values less than (TO_DATE('2019-03-01', 'YYYY-MM-DD')),
partition p_201903 values less than (TO_DATE('2019-04-01', 'YYYY-MM-DD')),
partition p_201904 values less than (TO_DATE('2019-05-01', 'YYYY-MM-DD')),
partition p_201905 values less than (TO_DATE('2019-06-01', 'YYYY-MM-DD')),
partition p_201906 values less than (TO_DATE('2019-07-01', 'YYYY-MM-DD')),
partition p_201907 values less than (TO_DATE('2019-08-01', 'YYYY-MM-DD')),
partition p_201908 values less than (TO_DATE('2019-09-01', 'YYYY-MM-DD')),
partition p_201909 values less than (TO_DATE('2019-10-01', 'YYYY-MM-DD')),
partition p_201910 values less than (TO_DATE('2019-11-01', 'YYYY-MM-DD')),
partition p_201911 values less than (TO_DATE('2019-12-01', 'YYYY-MM-DD')),
partition p_201912 values less than (TO_DATE('2020-01-01', 'YYYY-MM-DD')),
partition p_202001 values less than (TO_DATE('2020-02-01', 'YYYY-MM-DD')),
partition p_202002 values less than (TO_DATE('2020-03-01', 'YYYY-MM-DD'))
);
--數據的插入
insert into global_part_tab (id,deal_date,area_code,nbr,contents)
select rownum,
to_date( to_char(sysdate-365,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'),
ceil(dbms_random.value(590,599)),
ceil(dbms_random.value(18900000001,18999999999)),
rpad('*',400,'*')
from dual
connect by rownum <= 1000000;
commit;
--在global_part_tab表建本地索引:
create index id_idx_global on global_part_tab(id) ;
然后收集兩張表的統計信息:
exec dbms_stats.gather_table_stats('sys','global_part_tab');
exec dbms_stats.gather_table_stats('sys','local_part_tab');
首先我們來比較運行時間以及執行計划:
select index_name, partition_name, status,global_stats
from user_ind_partitions
where index_name='ID_IDX_LOCAL';
select index_name, status
from user_indexes
where index_name='ID_IDX_GLOBAL';
1) 查看不知道分區條件的特定值
SELECT * FROM LOCAL_PART_TAB WHERE ID=3000;
SELECT * FROM global_PART_TAB WHERE ID=3000;
這個cpu 成本差距差的不是一點點呀!!
第一個本地索引是利用索引范圍掃描,在通過rowid回表,但是后面還通過分區內的掃描;
第二個全局索引直接是索引范圍掃描,通過全局索引rowid回表返回結果。
前者cpu成本142,后者才4,幾十倍的差距。
2) 查看不知道分區條件的查看多個值
SELECT * FROM LOCAL_PART_TAB WHERE ID>=3000 and id <=3500;
SELECT * FROM global_PART_TAB WHERE ID>=3000 and id <=3500;
3) 查看某個分區條件的值
SELECT *
FROM LOCAL_PART_TAB
WHERE DEAL_DATE >= TO_DATE('2019-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND DEAL_DATE <= TO_DATE('2019-05-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND AREA_CODE IN (591, 592)
AND ID BETWEEN 2000 AND 2300;
SELECT *
FROM GLOBAL_PART_TAB
WHERE DEAL_DATE >= TO_DATE('2019-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND DEAL_DATE <= TO_DATE('2019-05-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND AREA_CODE IN (591, 592)
AND ID BETWEEN 2000 AND 2300;
本次是查看單個主分區里面,兩個子分區的值。
同樣的語句可以看出,
第一個是通過索引范圍掃面,在通過rowid,最后通過分區內的掃描取得所需要的值,11行,且cpu 消耗26;
而利用全局索引掃面卻索引范圍掃面,在通過rowid直接就取得所需要的結果集,9行,cpu消耗302;
這兩個,單個分區以及子分區的的性能差距不是一點點的差異,10多倍
4) 查看多個分區條件的多個值
SELECT *
FROM LOCAL_PART_TAB
WHERE DEAL_DATE >= TO_DATE('2019-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND DEAL_DATE <= TO_DATE('2019-08-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND AREA_CODE IN (591, 592,593,594,595,596)
AND ID BETWEEN 2000 AND 2200;
SELECT *
FROM GLOBAL_PART_TAB
WHERE DEAL_DATE >= TO_DATE('2019-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND DEAL_DATE <= TO_DATE('2019-08-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND AREA_CODE IN (591, 592,593,594,595,596)
AND ID>100 AND ID<1000;
此種上面哪個實驗一樣,全局索引完敗差距不是一點點!
第一個是通過索引范圍掃面,在通過rowid,最后通過分區內的掃描取得所需要的值;
而利用全局索引掃面卻索引范圍掃面,在通過rowid直接就取得所需要的結果集(注意,一樣的不通過分區范圍掃描);
5) 結論
全局索引適中的場景
在整張表中按照(某個特定的值)要求快速得出特定的值(比如我要查詢一個會員賬號名字為xyz的人信息,恰好user_info這張表是分區表,且不知道時間,需要全表找,恰好姓名做了全局索引,相當於整張表找某個值),因為。
本地索引適用場景:
不需要進行全表查找某個值,比如需要查找特定的時間特定的值,此時本地索引占優勢,其中本地索引還有一個優點就是維護起來比較方便,除了exchange交換分區的不帶上including indexes update global本地索引會不可用,其他的都可用,維護成本更低,但是全局索引除了增加分區和exchange交換分區的帶上including indexes update global有效之外,其他的操作均會不可用,需要重建。
四.12.2c分區表新特性(測試是用的19c)
這些是Oracle數據庫12 c第2版(12.2.0.1)中的新功能,官網:
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/partition-create-tables-indexes.html#GUID-12150FFB-48E4-4169-9EBE-64974C1CEF2A
自動列表list分區
自動列表分區方法允許按需創建列表分區。自動列表分區表與常規列表分區表相似,不同之處在於此分區表更易於管理。您可以僅使用已知的分區鍵值來創建自動列表分區表。在將數據加載到表中時,如果所加載的分區鍵值與任何現有分區都不對應,則數據庫會自動創建一個新分區。由於分區是根據需要自動創建的,因此自動列表分區方法類似於現有的間隔分區方法。
CREATE TABLE sales_auto_list
(
salesman_id NUMBER(5),
salesman_name VARCHAR2(30),
sales_state VARCHAR2(20),
sales_amount NUMBER(10),
sales_date DATE
)
PARTITION BY LIST (sales_state) AUTOMATIC
(PARTITION P_CAL VALUES ('CALIFORNIA')
);
比如我插入新的列值(不是分區值)。
多列列表分區
多列列表分區使您可以基於多列的列表值對表進行分區。與單列列表分區類似,單個分區可以包含包含值列表的集合。
CREATE TABLE sales_by_region_and_channel
(deptno NUMBER,
deptname VARCHAR2(20),
quarterly_sales NUMBER(10,2),
state VARCHAR2(2),
channel VARCHAR2(1)
)
PARTITION BY LIST (state, channel)
(
PARTITION q1_northwest_direct VALUES (('OR','D'), ('WA','D')),
PARTITION q1_northwest_indirect VALUES (('OR','I'), ('WA','I')),
PARTITION q1_southwest_direct VALUES (('AZ','D'),('UT','D'),('NM','D')),
PARTITION q1_ca_direct VALUES ('CA','D'),
PARTITION rest VALUES (DEFAULT)
);
其他值存在一個分區里面。
自動list分區和間隔子分區的延遲段創建
自動list組合分區表和間隔子分區僅在存在數據的情況下創建子分區。此操作可以節省空間。在按需創建新分區時推遲創建子分區段可確保僅在插入第一個匹配行時才創建子分區段。
有關創建自動列表分區表的信息,請參閱創建表和索引時指定分區。
CREATE TABLE par(pk INT CONSTRAINT par_pk PRIMARY KEY, i INT)
PARTITION BY RANGE(i) INTERVAL (10)
(PARTITION p1 VALUES LESS THAN (10));
CREATE TABLE chi(fk INT NOT NULL, i INT,
CONSTRAINT chi_fk FOREIGN KEY(fk) REFERENCES par(pk))
PARTITION BY REFERENCE(chi_fk);
INSERT INTO par VALUES(15, 15);
INSERT INTO par VALUES(25, 25);
INSERT INTO par VALUES(35, 35);
commit;
SELECT table_name, partition_position, high_value, interval
FROM USER_TAB_PARTITIONS WHERE table_name IN ('PAR', 'CHI')
ORDER BY 1, 2;
只讀分區
您可以將表,分區和子分區設置為只讀狀態,以防止任何用戶或觸發器對數據進行意外的DML操作。
有關創建具有只讀分區的表的信息,請參閱創建具有只讀分區或子分區的表。
CREATE TABLE orders_read_write_only (
order_id NUMBER (12),
order_date DATE CONSTRAINT order_date_nn NOT NULL,
state VARCHAR2(2)
) READ WRITE
PARTITION BY RANGE (order_date)
SUBPARTITION BY LIST (state)
( PARTITION order_p1 VALUES LESS THAN (TO_DATE ('01-DEC-2015','DD-MON-YYYY')) READ ONLY
( SUBPARTITION order_p1_northwest VALUES ('OR', 'WA'),
SUBPARTITION order_p1_southwest VALUES ('AZ', 'UT', 'NM')
),
PARTITION order_p2 VALUES LESS THAN (TO_DATE ('01-MAR-2016','DD-MON-YYYY'))
( SUBPARTITION order_p2_northwest VALUES ('OR', 'WA'),
SUBPARTITION order_p2_southwest VALUES ('AZ', 'UT', 'NM') READ ONLY
),
PARTITION order_p3 VALUES LESS THAN (TO_DATE ('01-JUL-2016','DD-MON-YYYY'))
(
SUBPARTITION order_p3_northwest VALUES ('OR', 'WA') READ ONLY,
SUBPARTITION order_p3_southwest VALUES ('AZ', 'UT', 'NM')
)
);
經測試,子分區,主分區都不能刪除。
將非分區表轉換為分區表(生產適用)
通過將MODIFY子句添加到ALTER TABLESQL語句,可以將非分區表轉換為分區表。另外,ONLINE可以指定關鍵字,從而在進行轉換時啟用並發DML操作。
有關在線轉換為分區表的信息,請參閱將非分區表轉換為分區表。
通過將MODIFY
子句添加到ALTER
TABLE
SQL語句,可以將非分區表轉換為分區表。
另外,ONLINE
可以指定關鍵字,從而在進行轉換時啟用並發DML操作。
以下是ALTER TABLE
使用ONLINE
關鍵字在線轉換為分區表的語句示例。
ALTER TABLE employees_convert MODIFY
PARTITION BY RANGE (employee_id) INTERVAL (100)
( PARTITION P1 VALUES LESS THAN (100),
PARTITION P2 VALUES LESS THAN (500)
) ONLINE
UPDATE INDEXES
( IDX1_SALARY LOCAL,
IDX2_EMP_ID GLOBAL PARTITION BY RANGE (employee_id)
( PARTITION IP1 VALUES LESS THAN (MAXVALUE)
)
);
create user c##test identified by "test";
grant dba,resource,connect to c##test;
conn c##test/test
CREATE TABLE TEST as SELECT * FROM dba_objects ;
create bitmap index bitidx on TEST(object_type);
update test set object_id=rownum;
commit;
ALTER TABLE test MODIFY PARTITION BY RANGE(object_id) INTERVAL (10000) ( PARTITION P1 VALUES LESS THAN (10000)) ONLINE UPDATE INDEXES (BITIDX local);
只需指定第一個分區就可以了。
注意object_id 不能為空啊,不能定義原始的值,bitmap index自動可以轉換成local index。
使用UPDATE INDEX子句時的注意事項
使用該UPDATE INDEXES子句時,請注意以下幾點。
- 此子句可用於更改索引的分區狀態和要轉換的索引的存儲屬性。
- 規范UPDATE INDEXES條款是可選的。
維護索引,以便在線和離線轉換為分區表。
- 該子句不能更改定義原始索引列表的列。
- 此子句不能更改索引或任何其他索引屬性的唯一性屬性。
- 如果您沒有為任何索引指定表空間,那么以下表空間默認值適用。
- 轉換后的本地索引與表分區並置。
- 轉換后的全局索引與未分區表上原始全局索引位於同一表空間中。
- 如果未指定該INDEXES子句或該INDEXES子句未指定原始非分區表上的所有索引,則以下默認行為適用於所有未指定的索引。
- 全局分區索引保持不變,並保留原始分區形狀。
- 非前綴索引成為全局非分區索引。
- 前綴索引將轉換為本地分區索引。
前綴表示分區鍵列包含在索引定義中,但是索引定義不限於僅包含分區鍵。
- 位圖索引成為本地分區索引,無論它們是否帶前綴。
位圖索引必須始終是本地分區索引。
- 如果存在域索引,則無法執行轉換操作
創建用於分區表交換的表
可以使用該FOR EXCHANGE WITH子句創建表,使其與分區表的形狀完全匹配,並且符合分區交換命令的要求,但不創建索引作為此命令的操作。由於此功能提供了未分區表和分區表之間的精確匹配,因此是對CREATE TABLE AS SELECT語句的改進。
有關創建與分區表進行交換的表的信息,請參閱創建與分區表進行交換的表。
個人覺得分區交換意義不大,沒有關注。
篩選的分區維護操作(多了一個merge)
分區維護操作支持添加數據過濾,從而實現分區和數據維護的結合。過濾后的分區維護操作僅保留滿足數據過濾要求的數據,作為分區維護的一部分。數據過濾的能力適用於MOVE PARTITION,MERGE PARTITION,和SPLIT PARTITION。
ALTER TABLE orders_move_part
MOVE PARTITION q1_2016 TABLESPACE open_orders COMPRESS ONLINE
INCLUDING ROWS WHERE order_state = 'open';
使用SPLIT操作進行在線分區維護(這個前面有)
SPLIT支持將操作進行分區維護作為在線操作,並使用ONLINE針對堆組織表的關鍵字,從而在進行分區維護操作時啟用並發DML操作。
有關拆分分區的信息,請參閱關於拆分分區和子分區。
ALTER TABLE transactions
SPLIT PARTITION FOR(TO_DATE('01-MAY-2007','dd-MON-yyyy'))
AT (TO_DATE('15-MAY-2007','dd-MON-yyyy'));
創建一個分區的外部表(這個不做實驗了)
支持對外部表進行分區,以更好地優化已分區外部表上的查詢。
CREATE TABLE sales (loc_id number, prod_id number, cust_id number, amount_sold number, quantity_sold number)
ORGANIZATION EXTERNAL
(TYPE oracle_loader
DEFAULT DIRECTORY load_d1
ACCESS PARAMETERS
( RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
NOBADFILE
LOGFILE log_dir:'sales.log'
FIELDS TERMINATED BY ","
)
)
REJECT LIMIT UNLIMITED
PARTITION BY RANGE (loc_id)
(PARTITION p1 VALUES LESS THAN (1000) LOCATION ('california.txt'),
PARTITION p2 VALUES LESS THAN (2000) DEFAULT DIRECTORY load_d2 LOCATION ('washington.txt'),
PARTITION p3 VALUES LESS THAN (3000))
;
其它特性
其它特性,比如創建一個外部的分區表:
CREATE TABLE sales (loc_id number, prod_id number, cust_id number, amount_sold number, quantity_sold number)
ORGANIZATION EXTERNAL
(TYPE oracle_loader
DEFAULT DIRECTORY load_d1
ACCESS PARAMETERS
( RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
NOBADFILE
LOGFILE log_dir:'sales.log'
FIELDS TERMINATED BY ","
)
)
REJECT LIMIT UNLIMITED
PARTITION BY RANGE (loc_id)
(PARTITION p1 VALUES LESS THAN (1000) LOCATION ('california.txt'),
PARTITION p2 VALUES LESS THAN (2000) DEFAULT DIRECTORY load_d2 LOCATION ('washington.txt'),
PARTITION p3 VALUES LESS THAN (3000));
使用虛擬列分區(常用於自動分區,生產減少自動維護成本)
通過分區,虛擬列可以用作任何常規列。
使用虛擬列時,支持所有分區方法,包括間隔分區和復合分區的所有不同組合。用作分區列的虛擬列不能使用對PL / SQL函數的調用。
以下示例顯示了sales使用虛擬列作為子分區鍵按范圍范圍進行分區的表。虛擬列通過乘以amount_sold和來計算銷售的總價值quantity_sold。如示例所示,虛擬列也支持行移動。如果啟用了行移動,則如果虛擬列的值評估為屬於另一個分區的值,那么行將從一個分區遷移到另一個分區。
CREATE TABLE sales
( prod_id NUMBER(6) NOT NULL
, cust_id NUMBER NOT NULL
, time_id DATE NOT NULL
, channel_id CHAR(1) NOT NULL
, promo_id NUMBER(6) NOT NULL
, quantity_sold NUMBER(3) NOT NULL
, amount_sold NUMBER(10,2) NOT NULL
, total_amount AS (quantity_sold * amount_sold)
)
PARTITION BY RANGE (time_id) INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
SUBPARTITION BY RANGE(total_amount)
SUBPARTITION TEMPLATE
( SUBPARTITION p_small VALUES LESS THAN (1000)
, SUBPARTITION p_medium VALUES LESS THAN (5000)
, SUBPARTITION p_large VALUES LESS THAN (10000)
, SUBPARTITION p_extreme VALUES LESS THAN (MAXVALUE)
)
(PARTITION sales_before_2007 VALUES LESS THAN
(TO_DATE('01-JAN-2007','dd-MON-yyyy'))
)
ENABLE ROW MOVEMENT
PARALLEL NOLOGGING;
比如我建一個自動按照天分區,list 子分區的表
CREATE TABLE sales_list
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE NOT NULL
, channel_id CHAR(1)
, Platform varchar2(10) NOT NULL
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id) INTERVAL (NUMTODSINTERVAL(1,'day'))
SUBPARTITION BY list(Platform)
SUBPARTITION TEMPLATE
( SUBPARTITION p_a VALUES ('a')
, SUBPARTITION p_b VALUES ('b')
, SUBPARTITION p_c VALUES ('c')
, SUBPARTITION p_d VALUES ('d')
)
(PARTITION sales_before_2007 VALUES LESS THAN
(TO_DATE('01-JAN-2007','dd-MON-yyyy'))
)
ENABLE ROW MOVEMENT
PARALLEL NOLOGGING;
注意子分區超范圍了,不能進行數據插入。
只能通過單獨加子分區了;
alter table sales_list modify PARTITION SALES_BEFORE_2007 add SUBPARTITION p_e VALUES ('e');
值得注意的是:
比如說我需要向主分區表加上一個子分區,只需要讓啟示分區添加子分區就行了。
比如說:
create table USER_AGENT_REBATE_RESULT_PART
(
id INTEGER not null,
platform_ident VARCHAR2(45),
object_type_cd VARCHAR2(30),
user_id INTEGER,
user_name VARCHAR2(20),
begin_rebate_dtt TIMESTAMP(6),
end_rebate_dtt TIMESTAMP(6),
sys_game_level_code_id INTEGER,
gameplay_class_name VARCHAR2(50),
effective_bet_amt NUMBER(22,2),
rebate_rate NUMBER(10,4),
rebate_amt NUMBER(22,2),
rebate_administrative_amt NUMBER(10,2),
web_profit_amt NUMBER(22,2),
commision_rebate_rate NUMBER(11,3),
commision_rebate_amt NUMBER(22,2),
commision_amt NUMBER(10,2),
bet_num INTEGER,
bet_amt NUMBER(22,2),
rebate_level_name VARCHAR2(30),
rebate_batch VARCHAR2(30),
rebate_dtt TIMESTAMP(6),
rpt_date DATE,
rebate_st_cd VARCHAR2(1),
confirm_rebate_amt NUMBER(22,2),
sub_rebate_batch VARCHAR2(30),
sys_game_level_code3_id INTEGER,
sys_game_level_code2_id INTEGER,
under_user_id INTEGER,
under_user_name VARCHAR2(50),
under_ind CHAR(1) default '0'
)
PARTITION BY RANGE(RPT_DATE) INTERVAL (NUMTODSINTERVAL(1, 'DAY'))
subpartition BY LIST (platform_ident)
(
PARTITION RPT_DATE_20171223 VALUES LESS THAN(TO_DATE('2017-12-24', 'YYYY-MM-DD'))
(
SUBPARTITION rpt_date_aj VALUES('aj'),
SUBPARTITION rpt_date_ap VALUES('ap'),
SUBPARTITION rpt_date_af VALUES('af'),
SUBPARTITION rpt_date_ce VALUES('ce'),
SUBPARTITION rpt_date_ax VALUES('ax'),
SUBPARTITION rpt_date_bc VALUES('bc'),
SUBPARTITION rpt_date_bj VALUES('bj'),
SUBPARTITION rpt_date_az VALUES('az'),
SUBPARTITION rpt_date_nb VALUES('nb')
) )
tablespace NB_TBS_YOBET nologging;
INSERT /*+PARALLEL(8)*/ INTO USER_AGENT_REBATE_RESULT_PART
SELECT * FROM USER_AGENT_REBATE_RESULT WHERE RPT_DATE <= DATE'2018-06-01';
然后插入了數據;
后面由於業務需要,需要加一個’hh’,子分區:
alter table USER_AGENT_REBATE_RESULT_PART modify partition RPT_DATE_20171223 add subpartition RPT_DATE_hh values ('hh');
然后:
INSERT /*+PARALLEL(8)*/ INTO USER_AGENT_REBATE_RESULT_PART
SELECT ID, 'hh', OBJECT_TYPE_CD, USER_ID, USER_NAME, BEGIN_REBATE_DTT, END_REBATE_DTT, SYS_GAME_LEVEL_CODE_ID, GAMEPLAY_CLASS_NAME, EFFECTIVE_BET_AMT, REBATE_RATE, REBATE_AMT, REBATE_ADMINISTRATIVE_AMT, WEB_PROFIT_AMT, COMMISION_REBATE_RATE, COMMISION_REBATE_AMT, COMMISION_AMT, BET_NUM, BET_AMT, REBATE_LEVEL_NAME, REBATE_BATCH, REBATE_DTT, RPT_DATE, REBATE_ST_CD, CONFIRM_REBATE_AMT, SUB_REBATE_BATCH, SYS_GAME_LEVEL_CODE3_ID, SYS_GAME_LEVEL_CODE2_ID, UNDER_USER_ID, UNDER_USER_NAME, UNDER_IND FROM USER_AGENT_REBATE_RESULT WHERE RPT_DATE <= DATE'2018-06-01';
完成,即表的結構變成每個主分區都有該子分區的值。
12c部分分區索引(12.1.01)
分區表的部分索引
您可以在表分區的子集上創建本地索引和全局索引,從而在創建索引時提供更大的靈活性。
使用默認表索引屬性支持此功能。創建或更改表時,可以為表或其分區指定默認的索引屬性。表索引屬性僅用於部分索引。
當PARTIAL在表上創建索引時:
本地索引:如果為表分區打開索引,則創建索引分區可用,否則將不可用。您可以通過在索引或索引分區級別上指定USABLE/ 來覆蓋此行為UNUSABLE。
全局索引:僅包括已打開索引的那些分區,而排除其他分區。
唯一索引或用於強制執行唯一約束的索引不支持此功能。FULL如果FULL未PARTIAL指定,則為默認值。
默認情況下,任何索引都將創建為FULL索引,從而使索引與表索引屬性分離。
該INDEXING子句也可以在分區和子分區級別上指定。
以下SQL DDL使用這些項目創建一個表:
分區ORD_P1和ORD_P3包含在所有部分全局索引中
PARTIAL默認情況下,創建與以上兩個表分區相對應的本地索引分區(對於創建的索引)。
其他分區將從所有部分全局索引中排除,並在本地索引中無法創建(對於創建的索引PARTIAL)。
12c統計信息
11g時,如果一個表上啟用了增量統計信息,當一個分區的一行更新后,那么這個分區上的統計信息就被認為是過期的,如果要生成全局信息則必須要重新收集這個分區的統計信息。
12c有一個新的選項INCREMENTAL_STALENESS,能讓你去控制什么時候分區統計信息被認為是過期的或者已經不適合用來生成全局統計信息了。默認這個值是NULL,表示分區有值變更時就立刻認為是過期(跟11g一樣)。
它也可以設成USE_STALE_PERCENT
或者USE_LOCKED_STATS,USE_STALE_PERCENT
,表示變化的行數所占百分比小於設置的STALE_PRECENTAGE
值時(默認10%),分區級別的統計信息一直被認為可用。USE_LOCKED_STATS
表示如果一個分區的統計信息被鎖定了,那么它就可以被用來生成全局統計信息而不用考慮這個分區從上次收集統計信息到現在有多少行記錄做了變更。
BEGIN
DBMS_STATS.SET_TABLE_PREFS (
ownname => 'c##test',
tabname => 'test',
pname => 'INCREMENTAL_STALENESS',
pvalue => 'USE_STALE_PERCENT');
END;
/
BEGIN
DBMS_STATS.SET_TABLE_PREFS (
ownname => 'c##test',
tabname => 'test',
pname => 'STALE_PERCENT',
pvalue => 2);
END;
/
查看全局統計信息:
select TABLE_NAME,ROW_MOVEMENT,NUM_ROWS,LAST_ANALYZED from user_tables;
查看分區統計信息:
select table_name,partition_name,num_rows,last_analyzed from user_tab_partitions where table_name='TEST';
很尷尬的是,增量統計沒有生效,然后我收集最后一個分區(SYS_P1079)統計信息,設為自動,然后整個分區表全局的以及分區統計信息都發生了變化。
begin
dbms_stats.gather_table_stats (
ownname => 'c##test',
tabname => 'TEST',
partname => 'SYS_P1079',
granularity => 'AUTO'
);
end;
/
select TABLE_NAME,ROW_MOVEMENT,NUM_ROWS,LAST_ANALYZED from user_tables;
主機時間不准 我調了一下。
select table_name,partition_name,num_rows,last_analyzed from user_tab_partitions where table_name='TEST';
后面再試了一下,整個全局統計信息變了,再一定的比例范圍內,分區統計信息只會收集該分區的統計信息。