使用存储过程定期批量删除数据

部署运行你感兴趣的模型镜像

一、环境准备

数据库中创建存放日志的路径:

create directory LOG_DIR as '/home/oracle/clean_log';
grant read,write on directory LOG_DIR to GAPS41;

二、创建日志存储过程

create or replace procedure gaps41.PUT_INTO_FILE(table_name  in varchar2,
                                                 l_delete    in number,
                                                 column_name in varchar2,
												 min_data	 in varchar2,
                                                 s_time      in varchar2,
                                                 e_time      in varchar2,
												 flag		 in varchar2) is
  file_handle utl_file.file_type;
  file_name   varchar2(20);
begin
  file_name   := to_char(sysdate, 'yyyymmdd') || '.log';
  file_handle := utl_file.fopen('LOG_DIR', file_name, 'a');
 if flag = '0' then
  utl_file.put_line(file_handle, '--------------------------------- START TIME :'|| s_time || ' ---------------------------------');
  utl_file.put_line(file_handle,'Delete table GAPS41.' || table_name || ' by column ' ||column_name || ' :');
  utl_file.put_line(file_handle, 'Totally ' || l_delete || ' records deleted!');
  utl_file.put_line(file_handle, 'The column min number: ' || min_data );
  utl_file.put_line(file_handle, '--------------------------------- FINISH TIME:' || e_time || ' ---------------------------------');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
 else if flag = '1' then
  utl_file.put_line(file_handle, '--------------------------------- START TIME :'|| s_time || ' ---------------------------------');
  utl_file.put_line(file_handle,'');
  utl_file.put_line(file_handle,'Truncate table GAPS41.' || table_name || ' Complated !');
  utl_file.put_line(file_handle,'');
  utl_file.put_line(file_handle, '--------------------------------- FINISH TIME:' || e_time || ' ---------------------------------');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
  utl_file.put_line(file_handle, '');
   end if;
  end if;
  utl_file.fflush(file_handle);
  utl_file.fclose(file_handle);
end;
/

三、创建批量删除的存储过程

CREATE OR REPLACE PROCEDURE GAPS41.DEL_TAB_BY_DATES(del_date    in varchar2,
                                                    tname       in varchar2,
                                                    column_name in varchar2,
                                                    date_format in varchar2,
                                                    commit_l    in number) AS
BEGIN
  DECLARE
    dd       varchar2(30);
    tn       varchar2(30);
    cn       varchar2(30);
	min_d 	 varchar2(300);
	m_d		 varchar2(20);
    dtf      varchar2(30);
    c_rowid  varchar2(300);
    cu_sql   clob;
    d_sql    clob;
    s_time   varchar2(30);
    e_time   varchar2(30);
    l_delete number := 0;
    type refcursor is ref cursor;
    c1 refcursor;
    C_COMMIT CONSTANT PLS_INTEGER := commit_l;
  BEGIN
    dd     := del_date;
    tn     := tname;
    cn     := column_name;
    dtf    := date_format;
    s_time := to_char(sysdate, 'yyyy-mm-dd hh24:mm:ss');
    cu_sql := 'SELECT ROWID ROW_ID FROM GAPS41.' || tn || ' where ' || cn || ' <to_char(sysdate-' || dd || ','''||dtf||''')';
    --dbms_output.put_line(cu_sql);
    open c1 for cu_sql;
  
    LOOP
      fetch c1
        into c_rowid;
      exit when c1%NOTFOUND;
      d_sql := 'DELETE FROM GAPS41.' || tn || ' WHERE ROWID = ''' ||c_rowid || '''';
      --dbms_output.put_line(d_sql);
      execute immediate d_sql;
    
      IF (MOD(C1%ROWCOUNT, C_COMMIT) = 0) THEN
      
        COMMIT;
        DBMS_LOCK.SLEEP(3);
      END IF;
    END LOOP;
    l_delete := l_delete + C1%ROWCOUNT;
    close c1;
    COMMIT;
	min_d :='select min('||cn ||') from GAPS41.'||tn;
	execute immediate min_d into m_d;
    e_time := to_char(sysdate, 'yyyy-mm-dd hh24:mm:ss');
    GAPS41.PUT_INTO_FILE(tn, l_delete,cn,m_d,s_time, e_time,0);
  END;
END;
/

四、创建执行删除的存储过程

CREATE OR REPLACE PROCEDURE GAPS41.DO_CLEAN(days  in varchar2,
                                            lines in number) is
BEGIN
  DECLARE
    d varchar2(20);
    l number;
    t clob;
    cursor t1 is
      select distinct table_name tn,
                      decode(table_name,
                             'IBPS_COMM_RECV',
                             'SENDDATE',
                             'IBPS_COMM_SEND',
                             'SENDDATE',
                             'IBPS_PAY_RELAT_REG',
                             'PLTDATE',
                             'IBPS_PAY_TRANS_REG',
                             'WKDT',
                             'IBPS_TXNET',
                             'TXNETGDT',
                             'UPSS_COREBKSERIAL',
                             'PLTDATE') cn
        from dba_tab_columns
       where TABLE_NAME IN ('IBPS_CHKBUSI_TMP_REG',
                            'IBPS_COMM_RECV',
                            'IBPS_COMM_SEND',
                            'IBPS_CORECHK_TEMP',
                            'IBPS_PAY_RELAT_REG',
                            'IBPS_PAY_TRANS_REG',
                            'IBPS_TXNET',
                            'UPSS_COREBKSERIAL')
         AND OWNER = 'GAPS41';
  BEGIN
    d := days;
    l := lines;
    for t_name in t1 loop
      if t_name.tn IN ('IBPS_CHKBUSI_TMP_REG', 'IBPS_CORECHK_TEMP') then
        t := 'truncate table GAPS41.' || t_name.tn;
        execute immediate t;
        --dbms_output.put_line(t);
        GAPS41.PUT_INTO_FILE(t_name.tn,
                             '0',
                             '',
							 '0',
                             to_char(sysdate, 'yyyy-mm-dd hh24:mm:ss'),
                             to_char(sysdate, 'yyyy-mm-dd hh24:mm:ss'),'1');
      else
        if t_name.tn in ('IBPS_PAY_TRANS_REG', 'IBPS_TXNET') then
          GAPS41.DEL_TAB_BY_DATES(d, t_name.tn, t_name.cn, 'yyyy-mm-dd', l);
        else
          GAPS41.DEL_TAB_BY_DATES(d, t_name.tn, t_name.cn, 'yyyymmdd', l);
        end if;
      end if;
    end loop;
  END;
END;
/

五、按清理协议清楚历史数据

5.1 调用现有的存储过程清楚数据

--使用DO_CLEAN
declare i number;
begin
for i in reverse 369 .. 360 loop
 GAPS41.DO_CLEAN(i,'10000');
end loop;
end;
/

--使用DEL_TAB_BY_DATES
exec GAPS41.DEL_TAB_BY_DATES(180,'IBPS_PAY_TRANS_REG','WKDT','yyyy-mm-dd','10000');

5.2 使用DBMS_PARALLEL清楚历史数据

CREATE OR REPLACE PROCEDURE Parallel_exec_delete(table_name in varchar2,
                         column_name in varchar2,
                         day_num  in number,
                         date_type in varchar2,
						 parallel_level in number,
						 chunk_size in number) is
begin
declare
  tn varchar2(50);
  cn varchar2(10);
  dn number;
  dtp varchar2(15);
  
  vc_task varchar2(100);
  vc_sql varchar2(2000);
  n_try number;
  n_status number;
  p_level number;
  ck_size number;
  
  file_handle utl_file.file_type;
  file_name   varchar2(50);
begin
  tn := table_name;
  cn := column_name;
  dn := day_num;
  dtp := date_type;
  p_level := parallel_level;
  ck_size := chunk_size;
  
  file_name   := to_char(sysdate, 'yyyymmdd') || '_parallel_delete.log';
  file_handle := utl_file.fopen('LOG_DIR', file_name, 'a');
  utl_file.put_line(file_handle,'Begin task =====================');
  utl_file.put_line(file_handle,'Table  : '||tn);
  utl_file.put_line(file_handle,'Column : '||cn);
  utl_file.put_line(file_handle,'Time   : '||to_char(sysdate, 'hh24:mi:dd'));
  utl_file.fflush(file_handle);
  --utl_file.fclose(file_handle);
  
  --Define the Task
  vc_task := tn||'_'||cn||'_DELETE';
  dbms_parallel_execute.create_task(task_name => vc_task); 

  --Define the Spilt
  dbms_parallel_execute.CREATE_CHUNKS_BY_ROWID(task_name => vc_task,
                                               table_owner => 'GAPS41',
                                               table_name => tn,
                                               by_row => true,
                                               chunk_size => ck_size); 
  
  vc_sql := 'delete /*+ ROWID(dda) */ from GAPS41.'||tn||' where rowid between :start_id and :end_id AND '||cn||' <to_char(sysdate-' || dn || ','''||dtp||''')';

  --Run the task
  dbms_parallel_execute.run_task(task_name => vc_task,
                                 sql_stmt => vc_sql,
                                 language_flag => dbms_sql.native,
                                 parallel_level => p_level);
  
  utl_file.put_line(file_handle,'===================== Task Finished  ' ||to_char(sysdate, 'hh24:mi:dd'));
  utl_file.put_line(file_handle,'');
  utl_file.fflush(file_handle);
  utl_file.fclose(file_handle);
  
  --Controller
  n_try := 0;
  n_status := dbms_parallel_execute.task_status(task_name => vc_task);
  while (n_try<2 and n_status != dbms_parallel_execute.FINISHED) loop
     dbms_parallel_execute.resume_task(task_name => vc_task);
     n_status := dbms_parallel_execute.task_status(task_name => vc_task);
  end loop;        

  --Deal with Result
  dbms_parallel_execute.drop_task(task_name => vc_task);                                   
end;
end;
/ 


--执行清除
begin
	Parallel_exec_delete('IBPS_PAY_TRANS_REG','WKDT',90,'yyyy-mm-dd',20,10000);
end;
/

查看parallel执行状态

select task_name, chunk_type, JOB_PREFIX from user_parallel_execute_tasks where task_name like '%_DELETE';
select status, count(*) from user_parallel_execute_chunks WHERE task_name like '%_DELETE' group by status;

select chunk_id, task_name, status, start_rowid, end_rowid from user_parallel_execute_chunks where rownum<10;

select sum(bytes)/1024/1024 from dba_undo_extents where status='ACTIVE';

select owner, job_name, JOB_ACTION, SCHEDULE_TYPE, state, last_start_date from dba_scheduler_jobs where job_name like 'TASK$_%';

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### 使用存储过程和游标批量删除千万级数据的最佳实践 #### 存储过程的设计 在处理大规模数据时,存储过程是一种有效的方式。它可以在服务器端运行复杂的逻辑而无需多次往返客户端与数据库之间。对于批量删除操作,可以通过以下方式优化: 1. **事务管理** 大规模删除操作可能会导致锁表或日志文件膨胀等问题。因此,在存储过程中应显式控制事务行为。例如,关闭自动提交模式并手动提交事务可以显著提高效率[^3]。 2. **分批处理** 将大任务分解为多个小批次来执行,这样不仅可以降低内存消耗,还能减少锁定时间。每次只删除一定数量的记录(如1万条),完成后立即提交事务以释放资源。 3. **索引利用** 删除语句中的WHERE子句应当精确匹配目标行,从而充分利用现有索引来加速定位待删记录。如果可能的话,创建覆盖索引或将常用过滤列加入复合索引中能够进一步提升性能[^2]。 4. **游标的使用注意事项** - 对于小型数据集来说,`FAST_FORWARD`类型的游标往往表现良好;但对于超大数据量场景,则需谨慎评估其适用性。 - 如果能在结果集中直接计算汇总信息而非逐行迭代,则后者通常更优效率更高一些[^1]。 以下是实现上述策略的一个示例代码片段: ```sql DELIMITER $$ CREATE PROCEDURE delete_large_data(IN batch_size INT, IN total_rows BIGINT) BEGIN DECLARE done BOOLEAN DEFAULT FALSE; DECLARE current_id BIGINT; -- 游标定义 DECLARE cur CURSOR FOR SELECT id FROM your_table WHERE condition LIMIT total_rows; -- 当游标到达末尾时触发异常处理器 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO current_id; IF done THEN LEAVE read_loop; END IF; START TRANSACTION; DELETE FROM your_table WHERE id = current_id AND condition; COMMIT; -- 控制每批次大小 IF (total_rows MOD batch_size) = 0 THEN DO SLEEP(0.1); /* 避免过高并发 */ END IF; END LOOP; CLOSE cur; END$$ DELIMITER ; ``` 此脚本展示了如何通过循环读取ID列表并对它们逐一应用DELETE命令来进行渐进式的清理工作流程。同时引入了短暂延迟机制防止过度占用系统资源。 --- ### 性能调优技巧 除了以上提到的技术手段外,还有以下几个方面可以帮助改善整体效能: - **调整缓冲池参数**: 增加innodb_buffer_pool_size可以让更多页面驻留在RAM里而不是频繁访问磁盘. - **预分配空间给undo log**: 调整 innodb_undo_log_truncate 和其他相关配置项有助于缩短长时间运行事物期间产生的回滚段增长速度过快带来的负面影响 . - **监控慢查询日志**: 定期审查这些报告找出潜在瓶颈所在位置进而采取针对性措施解决. 最后提醒一点就是任何改动之前最好先做好充分测试验证新方案确实可行后再推广到生产环境当中去实施变更动作!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hannah_JK

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

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

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

打赏作者

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

抵扣说明:

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

余额充值