前提:
数据库仓库A(就拿oracle11g为例)中有两个用户user1和user2,现在有user1中有表ldm_table1,且表ldm_table1有数据5千万以上,ldm_table1中的数据是从其他库B(数据源)中抽取过来的,前期业务理解不够或者需求有变,数据有变动需要重新从B中抽取数据到A库表ldm_table1中。
重新抽取数据前想把原来的ldm_table1中的数据进行备份,备份到用户user2中,以备将来恢复(重新抽取可能出错等原因)。
前面差不多是废话,可能举例不恰当,反正就是想备份大表(5千万以上记录,我自己这么认为,相对的),或者大表之间数据存在相互拷贝的一些方法。
1.具体备份方法(这里写了16个并行,视情况而定):
1 |
create table user2.LDM_table1 nologging parallel (DEGREE 16) AS SELECT * FROM user1.LDM_table1; |
2、代码
1 |
truncate table user1.LDM_table1; |
3.现在想把user2.LDM_table1中数据再恢复到user1.LDM_table1中,具体sql如下(我们不再create table了,因为user1.LDM_table1已经存在,并且索引什么的都建立了,如果数据没有超过1亿):
1 2 3 4 5 |
alter table user1.LDM_table1 nologging; alter session enable parallel dml; insert /*+append parallel*/ into user1.LDM_table1 SELECT/*+parallel*/ * FROM user2.LDM_table1; COMMIT alter table user1.LDM_table1 logging;; |
4.数据再多一些,比如几个亿的,用3中方法有些慢,所以我目前觉得还是用create方法(上述1中提到的)好些。但是采用重新创建表的方法时,需要drop掉原来的表,并且要建立索引,具体sql如下:
a.采用1中方法,
1 |
create table user1.LDM_table1 nologging parallel (DEGREE 16) AS SELECT * FROM user2.LDM_table1; |
b.创建主键(主键创建加并行好像不起作用)
c.创建索引(这里加了24个并行,视情况)
1 |
create bitmap index user1.INDEX_LDM_table1_RQ on user1.LDM_table1 (RQ)parallel 24 local; |
d.如果需要收集统计信息,则执行
1 |
exec dbms_stats.gather_table_stats('USER1','LDM_TABLE1,CASCADE=>true,estimate_percent=>10,method_opt=>'for all columns size auto',degree=>16); |
5.如果表user1.LDM_table1表存在分区,那么重新恢复可就不是简单create table(上述方法1)就能行的,因为采用上述方法1会丢失分区,所以这时应该用另一种方法,具体sql如下:(注意必须写明各个字段,而字段后面不跟长度类型等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
create table user1.LDM_table1 ( aaa, bbb, ccc, .... ) partition by range (N_DM) ( partition P00000000000 values less than (' 5500000') tablespace TS_DAT_LDM pctfree 10 initrans 1 maxtrans 255 storage ( initial 160K next 1M minextents 1 maxextents unlimited ), partition P 5500000 values less than ('5501000') tablespace TS_DAT_LDM pctfree 10 initrans 1 maxtrans 255 storage ( initial 160K next 1M minextents 1 maxextents unlimited ), ........ ) select aaa, bbb, ccc, ..... from user2.LDM_table1; |
6.有时候需要将表user2.LDM_table1中的部分数据提交到表user1.LDM_table1中,如果采用上述3中的方法会觉得有些慢,可以采用分部提交或者就循环提交,每次提交100万,直至提交完毕,具体sql如下
–循环提交数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
declare cursor cur is select /*+parallel(16)*/* from user2.LDM_table1; type rec is table of cur%rowtype; recs rec; begin execute immediate 'alter table user1.LDM_table1 nologging'; execute immediate 'alter session enable parallel dml'; open cur; while (true) loop fetch cur bulk collect into recs limit 1000000; forall i in 1 .. recs.count insert /*+append parallel(8)*/into user1.LDM_table1 values recs (i); commit; exit when cur%notfound; end loop; close cur; execute immediate 'alter table user1.LDM_table1 logging'; end; / |
7.如果想删除大表user1.LDM_table1中的部分数据,比如从几亿数据中删除1000万,可能采用delete方法比较慢,所以我们可以采用循环删除的方法,具体sql如下:
–循环删除数据
1 2 3 4 5 6 7 8 9 10 11 12 |
declare v_cnt NUMBER:=0; BEGIN LOOP DELETE FROM user1.LDM_table1 WHERE y_dm LIKE '10025%' AND ROWNUM<=10000; v_cnt:=SQL%ROWCOUNT; COMMIT; EXIT WHEN v_cnt<=0; END LOOP END; / |
–加并行快点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
declare v_cnt NUMBER:=0; BEGIN execute immediate 'alter table user1.LDM_table1 nologging'; execute immediate 'alter session enable parallel dml'; LOOP DELETE/*+PARALLEL(16)*/ FROM user1.LDM_table1 WHERE y_dm LIKE '10025%' AND ROWNUM<=10000; v_cnt:=SQL%ROWCOUNT; COMMIT; EXIT WHEN v_cnt<=0; END LOOP END; / |
8.注意内容
如果索引很多(一般是超过5个,我觉得),可以考虑先删除索引,后加入数据,最后创建索引
9.自己理解比较少,只能写成这样,欢迎讨论。