最近项目中牵涉到把mysql中一个表的数据牵移oracle上来,并只保存三个月的数据,由于此表的数据增加量比较大,现在是每个月三百万,以后会更多,所
以oracle表在实现时考虑到完整的增加与删除的策略!
下面将记录再实现过程中所遇到的所有问题:
1.对于数据量的不断增加,由于跟据时间特性,所以采用按时间进行分区的方式实现
2.对于增加与删除分区,采用存储过程来实现,采用定时执行的存储过程JOB,每月增加与删除一次分区。
3.对于表字段自增采用序列的方式实现。
4.对于以前数据牵移,在表建好后,一部分数据再建立索引以前牵移,等牵移完整后,切换数据库,切换成功后再牵移另一部分数据。
对于表结构的实现以及存储过程的建立语法如下:(网上参考别人的方式,实现的)
创建序列:
drop sequence loginid_seq;
create sequence loginid_seq
minvalue 1
nomaxvalue
start with 1
increment by 1
nocache;
分区表结构创建:
drop table tb_domainmail_weblogin_log;
CREATE TABLE tb_domainmail_weblogin_log(
login_id number primary key,
domain varchar2(100) not null,
account_name varchar2(50) not null,
login_type varchar2(20) not null,
login_time date default sysdate,
login_ip varchar2(130) default NULL
)
partition by range(login_time)
(
partition P_weblogin_20100115 values less than(to_date('2010-01-15 12:00:00','YYYY-MM-DD HH24:mi:ss')),--测试所用
partition P_weblogin_20110115 values less than(to_date('2011-01-15 12:00:00','YYYY-MM-DD HH24:mi:ss')),
partition P_weblogin_20110215 values less than(to_date('2011-02-15 12:00:00','YYYY-MM-DD HH24:mi:ss'))
);
--增加一个分区
alter table tb_domainmail_weblogin_log add partition P_weblogin_20110315 values less than(to_date('2011-03-15 12:00:00','YYYY-MM-DD
HH24:mi:ss'));
--增加分区的存储过程
CREATE OR REPLACE PROCEDURE WEBLOGIN_ADD_PARTITION_PROC(
partNum NUMBER, --添加分区的个数
partDay NUMBER --分区之间的时间间隔
) AS
v_SqlExec VARCHAR2(2000); --DDL语句变量
v_PartDate VARCHAR2(20); --创建分区的日期(YYYYMMDD)
v_PartDate1 VARCHAR2(30); --创建分区的日期(YYYYMMDD)
v_err_num NUMBER; --ORA错误号
v_err_msg VARCHAR2(100); --错误描述
v_PartDate_max VARCHAR2(20); --test_log 表分区的最大日期
BEGIN
--查询已创建 tb_domainmail_weblogin_log 表分区的最大日期
--P_weblogin_20110215
select max(SUBSTR(partition_name,12,8)) into v_PartDate_max
from user_tab_partitions
WHERE table_name=UPPER('tb_domainmail_weblogin_log');
FOR i IN 1..partNum LOOP
--创建 tb_domainmail_weblogin_log 表分区
IF v_PartDate_max<to_char(sysdate+(i*partDay),'yyyymmdd') THEN
v_PartDate:=to_char(SYSDATE+(i*partDay),'YYYYMMDD');
v_PartDate1:=to_char(SYSDATE+(i*partDay),'YYYY-MM-DD HH24:mi:ss');
v_SqlExec:='ALTER TABLE tb_domainmail_weblogin_log ADD PARTITION P_WEBLOGIN_' || v_PartDate ||
' values less than (to_date(''' || v_PartDate1 || ''',''YYYY-MM-DD HH24:mi:ss''))';
dbms_output.put_line('创建 tb_domainmail_weblogin_log 表分区' || i || '='||v_SqlExec);
DBMS_Utility.Exec_DDL_Statement(v_SqlExec);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
v_err_num := SQLCODE;
v_err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('WEBLOGIN_ADD_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END WEBLOGIN_ADD_PARTITION_PROC;
--再次,建立删除分区的存储过程
CREATE OR REPLACE PROCEDURE WEBLOGIN_DROP_PARTITION_PROC(
beforeDays NUMBER --删除多少天前的分区
)
As
v_SqlExec VARCHAR2(2000); --DDL语句变量
v_err_num NUMBER; --ORA错误号
v_err_msg VARCHAR2(100); --错误描述
--查找beforeDays天前存在的 tb_domainmail_weblogin_log 表分区
cursor cursor_testlog_part is
select partition_name from user_tab_partitions
WHERE table_name=UPPER('tb_domainmail_weblogin_log')
AND SUBSTR(partition_name,12,8)<TO_CHAR(SYSDATE-beforeDays,'YYYYMMDD')
ORDER BY partition_name;
record_testlog_oldpart cursor_testlog_part%rowType;
BEGIN
open cursor_testlog_part;
loop
fetch cursor_testlog_part into record_testlog_oldpart;
exit when cursor_testlog_part%notfound;
--删除 tb_domainmail_weblogin_log 表分区
v_SqlExec:='ALTER TABLE tb_domainmail_weblogin_log DROP PARTITION ' ||
record_testlog_oldpart.partition_name;
dbms_output.put_line('删除tb_domainmail_weblogin_log表分区='||v_SqlExec);
DBMS_Utility.Exec_DDL_Statement(v_SqlExec);
end loop;
close cursor_testlog_part;
EXCEPTION
WHEN OTHERS THEN
v_err_num := SQLCODE;
v_err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('WEBLOGIN_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END WEBLOGIN_DROP_PARTITION_PROC;
/
--执行增加的存储过程:
CREATE OR REPLACE PROCEDURE WEBLOGIN_EXEC_ADD_PROC AS
v_err_num NUMBER; --ORA错误号
v_err_msg VARCHAR2(100); --错误描述
v_date VARCHAR2(2):='15'; --每个月的15号做此事。
BEGIN
--2代表创建一个分区,30代表分区大小为30天的数据。
IF v_date=to_char(SYSDATE,'DD') THEN
WEBLOGIN_ADD_PARTITION_PROC(2,'31');
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
v_err_num := SQLCODE;
v_err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('WEBLOGIN_EXEC_ADD_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END WEBLOGIN_EXEC_ADD_PROC;
--执行删除的存储过程:
CREATE OR REPLACE PROCEDURE WEBLOGIN_EXEC_DROP_PROC AS
v_err_num NUMBER; --ORA错误号
v_err_msg VARCHAR2(100); --错误描述
v_date VARCHAR2(2):='15'; --每个月的15号做此事。
BEGIN
--删除3个月前的数据 100代表100天
IF v_date=to_char(SYSDATE,'DD') THEN
WEBLOGIN_DROP_PARTITION_PROC(100);
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
v_err_num := SQLCODE;
v_err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('WEBLOGIN_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END WEBLOGIN_EXEC_DROP_PROC;
--建立JOB定时执行存储过程
create or replace procedure WEBLOGIN_JOBS_PROC as
job1 number; --每个月15号18点创建分区
job2 number; --每个月15号23点删除分区
v_err_num NUMBER; --ORA错误号
v_err_msg VARCHAR2(100); --错误描述
begin
dbms_job.submit(job1,'WEBLOGIN_EXEC_ADD_PROC;',sysdate,'SYSDATE + (18*60)/(24*60)');
dbms_job.submit(job2,'WEBLOGIN_EXEC_DROP_PROC;',sysdate,'SYSDATE + (23*60)/(24*60)');
commit;
EXCEPTION
WHEN OTHERS THEN
v_err_num := SQLCODE;
v_err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('WEBLOGIN_JOBS_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
end WEBLOGIN_JOBS_PROC;
-执行定时工作JOB存储过程
execute WEBLOGIN_JOBS_PROC;
--删除存储过程
drop PROCEDURE WEBLOGIN_JOBS_PROC;
execute WEBLOGIN_EXEC_ADD_PROC;
以上为测试时实现的所有存储过程,都已经通过!