按月拆分数据库表--oracle

生产有一张日志表,数据量很大,需要按月进行存储,存储过程如下:

CREATE OR REPLACE PROCEDURE NEWLOG4_SUB_TABLE 
IS
    table_name1              VARCHAR2(50);
    create_table_sql         VARCHAR2(4000);
  insert_data_sql      VARCHAR2(4000);
  delete_data_sql      VARCHAR2(4000);
--  v_exists INT:=0;
   v_exists  NUMBER (10, 0);
BEGIN

  SELECT 'NEWLOG4_' || TO_CHAR(ADD_MONTHS(SYSDATE, -1), 'YYYYMM') INTO table_name1 FROM DUAL;

  select count(1) into v_exists from user_tables where table_name=UPPER(table_name1);
  --dbms_output.put_line(sname);
  --dbms_output.put_line(table_name1);
 if (v_exists <1)
   then
 -- dbms_output.put_line(sname);
  create_table_sql := 'create table ' || table_name1 || ' (
                             autudt          TIMESTAMP(6),
                  authentype      VARCHAR2(2000),
                  userid          VARCHAR2(2000),
                  orgid           VARCHAR2(2000),
                  org2id          VARCHAR2(2000),
                  realname        VARCHAR2(2000),
                  success         VARCHAR2(2000),
                  idpname         VARCHAR2(2000),
                  idpip           VARCHAR2(2000),
                  vistorip        VARCHAR2(2000),
                  vistorbrowser   VARCHAR2(2000),
                  spid            VARCHAR2(2000),
                  spurl           VARCHAR2(2000),
                  info            VARCHAR2(2000),
                  autdesc         VARCHAR2(2000),
                  taketime        VARCHAR2(2000),
                  orgnamefullpath VARCHAR2(2000),
                  ines            INTEGER default 0,
                  logid           VARCHAR2(32),
                  inputaccount    VARCHAR2(2000),
                  channel         NUMBER(32),
                  pushstate       NUMBER(2) default 0,
                   appid           VARCHAR2(50)
                      )';
  EXECUTE IMMEDIATE create_table_sql;
   commit;
  end if;

    --将FATHER_TABLE表中取上月记录 添加到新创建的分表中。
  insert_data_sql := 'INSERT INTO ' || table_name1 || ' SELECT * FROM NEWLOG4 WHERE autudt <(systimestamp - NUMTODSINTERVAL(30,''day'')) ';
  EXECUTE IMMEDIATE insert_data_sql;


  --删除FATHER_TABLE表中时间在上个月范围内的所有数据
  delete_data_sql := 'DELETE FROM NEWLOG4 WHERE autudt <(systimestamp-NUMTODSINTERVAL(30,''day''))';
  EXECUTE IMMEDIATE delete_data_sql;

    COMMIT;
 --EXCEPTION
  --WHEN OTHERS THEN
  --   ROLLBACK;
END NEWLOG4_SUB_TABLE;
create or replace procedure pro_exelog2 is
datetime INTEGER :=30; --Storage duration
v_name varchar2(40);
v_lastmouth varchar2(40);
v_count number:=0;
v_tbrecordname varchar2(10) :='newlog2_';
v_table varchar2(4000);
v_exists INT:=0;
begin
  select tb_name,v_tbrecordname||to_char(sysdate-datetime,'yyyymm') into v_name,v_lastmouth from tb_record where type =2 and status=1;
  select count(1) into v_count from tb_record where type =2 and tb_name=UPPER(v_lastmouth);
  if v_count=0 then
      begin
        update tb_record set status=0 where type =2;  -- erase status
        insert into tb_record(type,tb_name,status) values(2,UPPER(v_lastmouth),1); --insert new table record
        end;
  end if;
  select count(1) into v_exists from user_tables where table_name=UPPER(v_lastmouth);
  --create new table when time > 30 days
 if v_exists!=1 then
    begin
    v_table:='create table '||v_name||' (AUTUDT TIMESTAMP(6),AUTHENTYPE VARCHAR2(2000),USERID VARCHAR2(2000),ORGID VARCHAR2(800),ORG2ID VARCHAR2(800),REALNAME VARCHAR2(800),SUCCESS VARCHAR2(20),IDPNAME VARCHAR2(2000),IDPIP VARCHAR2(2000),VISTORIP VARCHAR2(2000),VISTORBROWSER VARCHAR2(2000),SPID VARCHAR2(2000),SPURL VARCHAR2(2000),INFO VARCHAR2(2000),AUTDESC VARCHAR2(2000),TAKETIME VARCHAR2(2000),ORGNAMEFULLPATH VARCHAR2(2000))';
    EXECUTE IMMEDIATE v_table;
    commit;
     end;
  end if;
  v_table:='insert into '||v_lastmouth||' select * from newlog2 where autudt <(sysdate-'||datetime||')'; --insert new data from old table
  EXECUTE IMMEDIATE v_table;
  commit;
  delete from newlog2 where autudt <(sysdate-datetime); --delete old data
  commit;
end pro_exelog2;
create or replace procedure pro_exelog1 is
datetime INTEGER :=30;
v_name varchar2(40);
v_lastmouth varchar2(40);
v_count int:=0;
v_table varchar2(4000);
v_exists INT:=0;
v_tbrecordname varchar2(10) :='newlog1_';
begin
  select tb_name ,v_tbrecordname||to_char(sysdate-datetime,'yyyymm') into v_name,v_lastmouth from tb_record where type =1 and status=1;
  select count(1) into v_count from tb_record where type =1 and tb_name=UPPER(v_lastmouth);
  if v_count=0 then
      begin
        update tb_record set status=0 where type=1;  -- erase status
        insert into tb_record(type,tb_name,status) values(1,UPPER(v_lastmouth),1); --insert new table record
        end;
  end if;
  
  select count(1) into v_exists from user_tables where table_name=UPPER(v_lastmouth);
  --create new table when time > 30 days
 if v_exists!=1 then
    begin
    v_table:='create table '||v_lastmouth||' (OPDT TIMESTAMP(6),OPUSERID VARCHAR2(32),OPUSERIP VARCHAR2(20),OPTYPE VARCHAR2(20),MAINOBJECTID VARCHAR2(32), MAINOBJECTTYPE VARCHAR2(20),MAINACTION VARCHAR2(50),BEFOREACTIONOBJECTJSONSTRING CLOB,AFTERACTIONOBJECTJSONSTRING CLOB,EXCCUTESTATUS VARCHAR2(2000),ERRORDESC VARCHAR2(2000),MAINOBJECTORG VARCHAR2(32),LOG_ID VARCHAR2(32) not null,PLATFORM VARCHAR2(20))';
    EXECUTE IMMEDIATE v_table;
    commit;
     end;
  end if;
  v_table:='insert into '||v_lastmouth||' select * from newlog1 where opdt <(sysdate-'||datetime||')'; --insert new data from old table
  EXECUTE IMMEDIATE v_table;
  commit;
 delete from newlog1 where opdt <(sysdate-datetime); --delete old data
 commit;
end pro_exelog1;
create or replace 
PROCEDURE PROC_CREATE_SUB_TABLE 
IS
    table_name              VARCHAR2(50);
    create_table_cursor     NUMBER(10);
    create_table_sql         VARCHAR2(1000);
  insert_data_sql      VARCHAR2(1000);
  delete_data_sql      VARCHAR2(1000);
  v_exists INT:=0;
BEGIN
  --生成分表的表名。
  SELECT 'NEWLOG4_' || TO_CHAR(ADD_MONTHS(SYSDATE, -1), 'YYYYMM') INTO table_name FROM DUAL;
  
  select count(1) into v_exists from user_tables where table_name=UPPER(table_name);
  if v_exists!=1  then 
  create_table_cursor := DBMS_SQL.OPEN_CURSOR;--打开游标
  --拼出创建表的SQL语句,并执行。
  create_table_sql := 'create table ' || table_name || ' (
													   autudt          TIMESTAMP(6),
								  authentype      VARCHAR2(2000),
								  userid          VARCHAR2(2000),
								  orgid           VARCHAR2(2000),
								  org2id          VARCHAR2(2000),
								  realname        VARCHAR2(2000),
								  success         VARCHAR2(2000),
								  idpname         VARCHAR2(2000),
								  idpip           VARCHAR2(2000),
								  vistorip        VARCHAR2(2000),
								  vistorbrowser   VARCHAR2(2000),
								  spid            VARCHAR2(2000),
								  spurl           VARCHAR2(2000),
								  info            VARCHAR2(2000),
								  autdesc         VARCHAR2(2000),
								  taketime        VARCHAR2(2000),
								  orgnamefullpath VARCHAR2(2000),
								  ines            INTEGER default 0,
								  logid           VARCHAR2(32),
								  inputaccount    VARCHAR2(2000),
								  channel         NUMBER(32),
								  pushstate       NUMBER(2) default 0
                      )';
    DBMS_SQL.PARSE(create_table_cursor, create_table_sql, DBMS_SQL.V7);
    DBMS_SQL.CLOSE_CURSOR(create_table_cursor);
   end if;

    --将FATHER_TABLE表中取上月记录 添加到新创建的分表中。
  insert_data_sql := 'INSERT INTO ' || table_name || ' SELECT * FROM NEWLOG4 WHERE autudt <(systimestamp + NumToYMInterval(-1, 'MONTH')) ';
           v_table:='insert into '||v_lastmouth||' select * from newlog2 where autudt <(sysdate-'||datetime||')';
  EXECUTE IMMEDIATE insert_data_sql;


  --删除FATHER_TABLE表中时间在上个月范围内的所有数据
  delete_data_sql := 'DELETE FROM NEWLOG4 WHERE autudt <(systimestamp + NumToYMInterval(-1, 'MONTH')) ';
  EXECUTE IMMEDIATE delete_data_sql;

    COMMIT;
  EXCEPTION
    WHEN OTHERS THEN
      ROLLBACK;
END PROC_CREATE_SUB_TABLE;
CREATE OR REPLACE PROCEDURE NEWLOG4_history_table
IS
  -- table_name1              VARCHAR2(50);
  -- create_table_sql         VARCHAR2(4000);
  -- insert_data_sql      VARCHAR2(4000);
  -- delete_data_sql      VARCHAR2(4000);
--  v_exists INT:=0;
  -- v_exists  NUMBER (10, 0);
   CURSOR cur IS
    select * from NEWLOG4 t where autudt <(systimestamp-NUMTODSINTERVAL(30,'day'))and pushstate='3';
    TYPE rec IS TABLE OF NEWLOG4%ROWTYPE;
    recs rec;
BEGIN
OPEN cur;
WHILE (TRUE) LOOP
FETCH cur BULK COLLECT
INTO recs LIMIT 5000;
FORALL i IN 1 .. recs.COUNT
INSERT INTO NEWLOG4_DAY_INTERVAL_PARTITION VALUES recs (i);
 COMMIT;
 EXIT WHEN cur%NOTFOUND;
 END LOOP;
 CLOSE cur;
 --EXCEPTION
  --WHEN OTHERS THEN
  --   ROLLBACK;
END NEWLOG4_history_table;
CREATE OR REPLACE PROCEDURE NEWLOG4_day_TABLE (delete_date in varchar2)
IS
  insert_data_sql      VARCHAR2(4000);
  delete_data_sql      VARCHAR2(4000);
   CURSOR cur IS
select * from NEWLOG4 t where TO_CHAR(t.autudt,'YYYY-MM-DD') = delete_date and pushstate='3';
TYPE rec IS TABLE OF NEWLOG4%ROWTYPE;
recs rec;
BEGIN
OPEN cur;
WHILE (TRUE) LOOP
FETCH cur BULK COLLECT
INTO recs LIMIT 5000;
FORALL i IN 1 .. recs.COUNT
--EXECUTE IMMEDIATE insert_data_sql;
INSERT INTO NEWLOG4_DAY_INTERVAL_PARTITION VALUES recs (i);
 COMMIT;
 EXIT WHEN cur%NOTFOUND;
 END LOOP;
 CLOSE cur;

 --EXCEPTION
  --WHEN OTHERS THEN
  --   ROLLBACK;
END NEWLOG4_day_TABLE;
CREATE OR REPLACE PROCEDURE NEWLOG4_SUB_test (delete_date in varchar2)
IS
   -- table_name1              VARCHAR2(50);
   -- create_table_sql         VARCHAR2(4000);
  insert_data_sql      VARCHAR2(4000);
  delete_data_sql      VARCHAR2(4000);
--  v_exists INT:=0;
 --  v_exists  NUMBER (10, 0);
   CURSOR cur IS
select * from NEWLOG4 t where TO_CHAR(t.autudt,'YYYY-MM-DD') = delete_date and pushstate='3';
TYPE rec IS TABLE OF NEWLOG4%ROWTYPE;
recs rec;
BEGIN
    --将FATHER_TABLE表中取上月记录 添加到新创建的分表中。
 -- insert_data_sql := 'INSERT INTO ' || table_name1 || ' SELECT * FROM NEWLOG4 WHERE autudt <(systimestamp - NUMTODSINTERVAL(30,''day'')) and pushstate=''3''';
 -- EXECUTE IMMEDIATE insert_data_sql;
 --insert_data_sql :='INSERT INTO '||history_table|| 'VALUES recs (i)'
OPEN cur;
WHILE (TRUE) LOOP
FETCH cur BULK COLLECT
INTO recs LIMIT 5000;
FORALL i IN 1 .. recs.COUNT
--EXECUTE IMMEDIATE insert_data_sql;
INSERT INTO NEWLOG4_202103_10 VALUES recs (i);
 COMMIT;
 EXIT WHEN cur%NOTFOUND;
 END LOOP;
 CLOSE cur;

--insert_data_sql :='alter session enable parallel dml';
  --EXECUTE IMMEDIATE insert_data_sql;
   -- delete_data_sql :='delete /*+parallel(12)*/  from NEWLOG4  nologging  where TO_CHAR(autudt,''YYYY-MM-DD'') =''2021-03-10''and pushstate=''3''';

   --delete_data_sql :='delete /*+parallel(12)*/  from NEWLOG4  nologging  where TO_CHAR(autudt,''YYYY-MM-DD'') =' ||delete_date|| 'and pushstate=''3''';
  --EXECUTE IMMEDIATE delete_data_sql;
   --COMMIT;
 --EXCEPTION
  --WHEN OTHERS THEN
  --   ROLLBACK;
END NEWLOG4_SUB_test;
2.alter table tab1 nologging;
  insert /*+ append */ into tab1 select * from tab2;
  commit;
  alter table tab1 logging;


  该方法会使得产生arch大大减少,并且在一定程度上提高时间,根据经验,千万级的数据可在45分钟内完成。但是请注意,该方法适合单进程的串行方式,如果当有多个进程同时运行时,后发起的进程会有enqueue的等待。注意此方法千万不能dataguard上用(不过要是在database已经force logging那也是不怕的,呵呵)!!



3. insert into tab1 select /*+ parallel */ * from tab2;
  commit;


  对于select之后的语句是全表扫描的情况,我们可以加parallel的hint来提高其并发,这里需要注意的是最大并发度受到初始化参数parallel_max_servers的限制,并发的进程可以通过v$px_session查看,或者ps -ef |grep ora_p查看。


4. alter session enable parallel dml;
  insert /*+ parallel */ into tab1 select * from tab2;
  commit;


  与方法2相反,并发的insert,尚未比较和方法2哪个效率更高(偶估计是方法2快),有测试过的朋友欢迎补充。

5.insert into tab1 select * from tab2 partition (p1);
  insert into tab1 select * from tab2 partition (p2);
  insert into tab1 select * from tab2 partition (p3);
  insert into tab1 select * from tab2 partition (p4);


  对于分区表可以利用tab1进行多个进程的并发insert,分区越多,可以启动的进程越多。我曾经试过insert 2.6亿行记录的一个表,8个分区,8个进程,如果用方法2,单个进程完成可能要40分钟,但是由于是有8个分区8个进程,后发进程有enqueue,所以因此需要的时间为40分钟×8;但是如果用方法5,虽然单个进程需要110分钟,但是由于能够并发进程执行,所以总共需要的时间就约为110分钟了。

6.DECLARE
  TYPE dtarray IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;
  v_col1 dtarray;
  v_col2 dtarray;
  v_col3 dtarray;
  BEGIN
  SELECT col1, col2, col3 BULK COLLECT
  INTO v_col1, v_col2, v_col3
  FROM tab2;
  FORALL i IN 1 .. v_col1.COUNT
  insert into tab1 WHERE tab1.col1 = v_col1;
  END;


  用批量绑定(bulk binding)的方式。当循环执行一个绑定变量的sql语句时候,在PL/SQL 和SQL引擎(engines)中,会发生大量的上下文切换(context switches)。使用bulk binding,能将数据批量的从plsql引擎传到sql引擎,从而减少上下文切换过程,提升效率。该方法比较适合于在线处理,不必停机
————————————————

7.sqlplus -s user/pwd< runlog.txt
  set copycommit 2;
  set arraysize 5000;
  copy from user/pwd@sid -
  to user/pwd@sid -
  insert tab1 using select * from tab2;
  exit
  EOF


  用copy的方法进行插入,注意此处insert没有into关键字。该方法的好处是可以设置copycommit和arrarysize来一起控制commit的频率,上面的方法是每10000行commit一次

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凤舞飘伶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值