看提交的的过程:
CREATE OR REPLACE PROCEDURE P_MS_MOVEMEDIATASK( i_time DATE ) AS v_time DATE; v_beginTime DATE; v_monthday VARCHAR2(4); v_month VARCHAR2(2); v_count NUMBER; v_sql VARCHAR2(5000); v_ret VARCHAR2(10); v_errMsg VARCHAR2(500); v_total NUMBER; BEGIN v_beginTime := SYSDATE; --转移31天前的数据 v_time := i_time; --取转移数据的monthday v_monthday := to_char(v_time,'mmdd'); --取转移数据的月份,按月分转移到不同的表里时用 v_month := to_char(v_time,'mm'); -- SELECT COUNT(1) INTO v_count FROM T_MS_MEDIA_TASK T WHERE T.MONTHDAY = v_monthday; v_total := v_count; WHILE(v_count > 0) LOOP --将要转移的数据RESERVE79字段置0 UPDATE T_MS_MEDIA_TASK T SET T.RESERVE79 = '0' WHERE T.MONTHDAY = v_monthday AND ROWNUM <= 50000; --每次最多提交50000条 --将待转移数据插入历史表中 按月插入不同历史表 动态SQL v_sql := 'insert into t_ms_media_task_his'||v_month ... ... EXECUTE IMMEDIATE v_sql; --删除转移过的数据 DELETE FROM T_MS_MEDIA_TASK T WHERE T.MONTHDAY = v_monthday AND T.RESERVE79 = '0'; COMMIT; --获取需要转移的数据条数 SELECT COUNT(1) INTO v_count FROM T_MS_MEDIA_TASK T WHERE T.MONTHDAY = v_monthday; END LOOP; EXCEPTION ... END P_MS_MOVEMEDIATASK; /就这个操作,每次的select都要扫描单分区,几千万的数据,以上过程中每50000条提交一次,后面还有大量的delete。
我的测试代码如下:
SQL> create table test1 2 (vid number , 3 v_date number, 4 v_data varchar2(100)) 5 partition by range(v_date) 6 (partition day_1 values less than (2 ), 7 partition day_2 values less than (3 ), 8 partition day_3 values less than (4 ), 9 partition day_4 values less than (5 ), 10 partition day_5 values less than (6 ), 11 partition day_6 values less than (7 ), 12 partition day_7 values less than (8 ), 13 partition day_8 values less than (9 ), 14 partition day_9 values less than (10), 15 partition day_10 values less than (11), 16 partition day_11 values less than (12), 17 partition day_12 values less than (13), 18 partition day_13 values less than (14), 19 partition day_14 values less than (15), 20 partition day_15 values less than (16), 21 partition day_16 values less than (17), 22 partition day_17 values less than (18), 23 partition day_18 values less than (19), 24 partition day_19 values less than (20), 25 partition day_20 values less than (21), 26 partition day_21 values less than (22), 27 partition day_22 values less than (23), 28 partition day_23 values less than (24), 29 partition day_24 values less than (25), 30 partition day_25 values less than (26), 31 partition day_26 values less than (27), 32 partition day_27 values less than (28), 33 partition day_28 values less than (29), 34 partition day_29 values less than (30), 35 partition day_30 values less than (31), 36 partition day_31 values less than (32), 37 partition day_max values less than (maxvalue) 38 ); Table created. SQL> SQL> insert into test1 2 (vid, 3 v_date, 4 v_data) 5 select 6 level , 7 mod(level,31)+1, 8 lpad(level,60,'0') 9 from dual 10 connect by level<=100000; 100000 rows created. SQL>commit; Commit complete. SQL> create index idx_1 on test1(vid) local; SQL>create index idx_2 on test1(vid,v_date) local; SQL> create table test2 as select*from test1 where 1=2; SQL> create index idx_3 on test2(vid,v_date); SQL> create table test3 2 (vid number , 3 v_date number, 4 v_data varchar2(100)) 5 partition by range(v_date) 6 (partition day_1 values less than (2 ), 7 partition day_2 values less than (3 ), 8 partition day_3 values less than (4 ), 9 partition day_4 values less than (5 ), 10 partition day_5 values less than (6 ), 11 partition day_6 values less than (7 ), 12 partition day_7 values less than (8 ), 13 partition day_8 values less than (9 ), 14 partition day_9 values less than (10), 15 partition day_10 values less than (11), 16 partition day_11 values less than (12), 17 partition day_12 values less than (13), 18 partition day_13 values less than (14), 19 partition day_14 values less than (15), 20 partition day_15 values less than (16), 21 partition day_16 values less than (17), 22 partition day_17 values less than (18), 23 partition day_18 values less than (19), 24 partition day_19 values less than (20), 25 partition day_20 values less than (21), 26 partition day_21 values less than (22), 27 partition day_22 values less than (23), 28 partition day_23 values less than (24), 29 partition day_24 values less than (25), 30 partition day_25 values less than (26), 31 partition day_26 values less than (27), 32 partition day_27 values less than (28), 33 partition day_28 values less than (29), 34 partition day_29 values less than (30), 35 partition day_30 values less than (31), 36 partition day_31 values less than (32), 37 partition day_max values less than (maxvalue) 38 ); Table created. SQL> alter table test1 exchange partition day_1 with table test2 including indexes; alter table test1 exchange partition day_1 with table test2 including indexes * ERROR at line 1: ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION SQL> !oerr ora 14098 14098, 00000, "index mismatch for tables in ALTER TABLE EXCHANGE PARTITION" // *Cause: The two tables specified in the EXCHANGE have indexes which are // not equivalent // *Action: Ensure that the indexes for the two tables have indexes which // follow this rule // For every non partitioned index for the non partitioned table, // there has to be an identical LOCAL index on the partitioned // table and vice versa. By identical, the column position, type // and size have to be the same. SQL> create index idx_4 on test2(vid); Index created. SQL> alter table test1 exchange partition day_1 with table test2 including indexes; Table altered. SQL> select DISTINCT index_name,status 2 From dba_ind_partitions 3 where index_name IN('IDX_1','IDX_2','IDX_3','IDX_4'); INDEX_NAME STATUS ------------------------------ -------- IDX_1 USABLE IDX_2 USABLE SQL> select INDEX_NAME,STATUS 2 from dba_indexes 3 where index_name IN('IDX_1','IDX_2','IDX_3','IDX_4'); INDEX_NAME STATUS ------------------------------ -------- IDX_4 VALID IDX_1 N/A IDX_2 N/A IDX_3 VALID SQL> create index idx_5 on test3(vid) local; Index created. SQL> create index idx_6 on test3(vid,v_date) local; Index created. SQL> alter table test3 exchange partition day_1 with table test2 including indexes; Table altered. SQL> select DISTINCT index_name,status 2 From dba_ind_partitions 3 where index_name IN('IDX_1','IDX_2','IDX_3','IDX_4','IDX_5','IDX_6'); INDEX_NAME STATUS ------------------------------ -------- IDX_1 USABLE IDX_2 USABLE IDX_5 USABLE IDX_6 USABLE SQL> select INDEX_NAME,STATUS 2 from dba_indexes 3 where index_name IN('IDX_1','IDX_2','IDX_3','IDX_4','IDX_5','IDX_6'); INDEX_NAME STATUS ------------------------------ -------- IDX_6 N/A IDX_4 VALID IDX_5 N/A IDX_1 N/A IDX_2 N/A IDX_3 VALID简单的测试完后,在生产测试环境中又测试一番,可以实施成功.方案确定,通过编写存储过程,建立job来定时完成任务
CREATE OR REPLACE PROCEDURE P_MS_MOVEMEDIATASK AS v_time DATE; v_month VARCHAR2(2); v_day VARCHAR2(2); v_count NUMBER; v_sql VARCHAR2(5000); v_ret VARCHAR2(10); v_errMsg VARCHAR2(500); BEGIN --转移31天前的数据 v_time := sysdate-31; --取转移数据的月份,按月分转移到不同的表里时用 v_month := to_char(v_time,'mm'); v_day := to_char(v_time,'dd'); ... --如果历史表该天分区中有数据,则不做转移 v_sql := 'SELECT COUNT(1) INTO :v_count FROM T_MS_MEDIA_TASK_HIS'||v_month||' PARTITION (P'||v_month||'_'||v_day||') WHERE ROWNUM=1'; --dbms_output.put_line(v_sql); EXECUTE IMMEDIATE v_sql into v_count; IF v_count > 0 THEN v_ret := '99999'; v_errMsg := '历史表T_MS_MEDIA_TASK_HIS'||v_month||'中P'||v_month||'_'||v_day||'分区存在数据,'||v_month||v_day||'数据未进行转移'; INSERT INTO T_MS_DBSTATE(CREATEDATE, ERRORCODE, ERRORINFO, MODULENAME) VALUES(SYSDATE, v_ret, v_errMsg, 'P_MS_MOVEMEDIATASK'); COMMIT; RETURN; --终止存储过程 END IF; --进行分区交换 T_MS_MEDIA_TASK <==> T_MS_MEDIA_TASK_CEN v_sql := 'ALTER TABLE T_MS_MEDIA_TASK EXCHANGE PARTITION P'||v_month||'_'||v_day||' WITH TABLE T_MS_MEDIA_TASK_CEN INCLUDING INDEXES'; --dbms_output.put_line(v_sql); EXECUTE IMMEDIATE v_sql; --进行分区交换T_MS_MEDIA_TASK_HIS?? <==> T_MS_MEDIA_TASK_CEN v_sql := 'ALTER TABLE T_MS_MEDIA_TASK_HIS'||v_month||' EXCHANGE PARTITION P'||v_month||'_'||v_day||' WITH TABLE T_MS_MEDIA_TASK_CEN INCLUDING INDEXES'; --dbms_output.put_line(v_sql); EXECUTE IMMEDIATE v_sql; ... EXCEPTION ... END P_MS_MOVEMEDIATASK; /简单记录,以备后用。