背景:公司要求將數據庫中表超過2G的表進行分區。剛好我們負責的表有5張大於2G的。所以需要進行表分區。
所謂分區,講的的通俗點,就是根據某個字段的範圍進行劃分,將表分成幾塊。以後查詢,維護都更加方便。
比如可以根據創建時間,2018年的數據放入一個分區,以後每3年存入一個分區。
實際環境:我負責的這個表,大小是12G作右,接近7千萬條數據。
因爲這個表已經使用了很多年了,剛開始建表的時候沒有考慮到數據會變的這麼大。所以沒有建分區。現在的思路是重新建立一張分區表和源表一模一樣,不同的是該表進行了分區。然後把7千萬條數據導入到該表。最後將兩個表互換名字。
難點:難點有幾個:1.導入數據,7千萬的數據不能簡單的insert...select。因爲它是自動commit。可能最後commit時服務器都撐爆了。 2.換名字。兩個表互換名字,如果將新表插入了數據,此時源表還在進行數據的增刪改怎麼辦,這樣數據就沒有同步了。
3.索引的問題,建表的時候不要建索引,數據插入完後再建索引。不然插入數據時效率較低。
實際操作:由於公司的保密,語句不能copy出來。
第一:根據源表創建分區表,根據創建時間字段,18年以前的數據爲一分區,後面每年一分區。
create table A_temp as select * from A where 1=0 partition by RANGE(create_time)
INTERVAL (numtoyminterval(1,'year'))
(partition part_t01 values less than(to_date('2018-01-01', 'yyyy-mm-dd')));
第二:表註釋和字段註釋以及默認值和不爲空的設置,付權限,同義詞。
comment on table A_temp is 'XXX';
comment on column A.xxx is 'ccc';......
第三:插入數據,採用並行插入,提供效率。儘量在用戶使用量小的時候做表分區。比如我們在晚上11:30部署,基本沒有用戶做增刪改操作。並且設置源表爲只讀。
alter table A read only;
//分批插入
declare
vd_start_date date;
vd_end_date date;
begin
vd_start_date:=to_date('20090301','YYYYMMDD'),
vd_end_date:=to_date('20191130','YYYYMMDD');
while vd_start_date<=vd_end_date
loop
insert /* append parallel(A,4) */ into A_temp A
select /* append parallel(T,4) */ from A
where created_date>=vd_start_date and
created_date<add_month(v_start_date,3);
commit;
vd_start_date:=add_month(vd_start_date,3);
end loop;
end;
/;
第五:建索引,約束。數據插入完後再建索引和約束。效率比較高
create index xxx on A_temp(xxx);...
第六:建同義詞。
create public synonym for A_temp;
第七:解除原表只讀。
alter table A read write;
第八:給新表賦權限:
grant select on A_temp to XXX;
第九:表名交換。
alter table A rename to A_new;
alter table A_temp rename to A;
這樣,就重新建了一張表A_temp.和表A一樣,並且是已經分區了的。從而替代了A.
最後可以刪除A_new.