Oralce-清除数据的两种思路

简介: Oralce-清除数据的两种思路

20191208102017599.png


数据量很大


思路: 关联的表数据量都很大,获取一次数据时间较长,可以考虑将数据一次性捞出来放到临时表中,只执行一次耗时取数据的查询,放到临时表中,然后通过游标获取临时表中的数据,去对应的表中删除。 同时考虑到业务高峰期,job执行尽量避开业务高峰期。


Warning: 第一次清理数据量比较大的时候,可以通过创建临时表的方式,待第一次清理完成后,后续过期数据数据量小的情况下,可以采用【数据量较少】这种方法加上JOB以及表分析来开展。

create or replace procedure Proc_Clean_Inventory_Data
authid current_user  is
  v_card_number voucher_card.card_number%type;
  v_goods_type_id gm_goods_inst.goods_type_id%type;
  v_goods_stat gm_goods_inst.goods_state%type;
  v_inventory_clean_record_num number(3);
  v_temp_inventory_index_num number(3);
  v_createRecordTableSql varchar2(4000);
  v_createTempTableIndexSql varchar2(4000);
  v_dropTableSql varchar2(4000);
  v_getDataSql varchar2(4000);
  --- create table temp_inventory_4_delete(card_number varchar2(60));
  -- cusrosr card_number collection   
  cursor cur_card_numbers is 
      select card_number from TEMP_INVENTORY_4_DELETE;
begin
  -- set value 
  v_goods_type_id :='V';
  v_goods_stat :='C';
  -- create temp table 
  v_getDataSql := 'create table TEMP_INVENTORY_4_DELETE as select card_number 
         from voucher_card vc
      where vc.card_number in
       (select goods_sn
          from gm_goods_inst
         where GOODS_TYPE_ID = '||chr(39)||v_goods_type_id||chr(39)||'
           and GOODS_STATE = '||chr(39)||v_goods_stat||chr(39)||'
           and state_date < sysdate - 50)'  ;    
   v_dropTableSql := 'drop table TEMP_INVENTORY_4_DELETE';  
   v_createTempTableIndexSql := 'create index IDX_CARD_NUMBER on TEMP_INVENTORY_4_DELETE (CARD_NUMBER)'; 
   v_createRecordTableSql :='create table inventory_clear_record(card_number VARCHAR2(60),create_time DATE)'; 
  -- check exists or not 
  select count(1) into v_inventory_clean_record_num  from user_tables ut where ut.TABLE_NAME = 'INVENTORY_CLEAR_RECORD';
  -- create inventory_clear_record for once
  if v_inventory_clean_record_num = 0 then 
    execute immediate v_createRecordTableSql ;
  end if ; 
  -- drop TEMP_INVENTORY_4_DELETE then recreate 
  execute immediate v_dropTableSql ;
  execute immediate v_getDataSql ;
  -- check exists or not 
  select count(1) into v_temp_inventory_index_num from user_indexes ui where ui.index_name = 'IDX_CARD_NUMBER';
  -- create index for TEMP_INVENTORY_4_DELETE
  if v_temp_inventory_index_num = 0 then 
    execute immediate v_createTempTableIndexSql ;
  end if ; 
  /******Clean expired Data in voucher_card And gm_goods_inst******/
  --open cur_card_numbers,execute the cursor define sql
  open cur_card_numbers;
  --begin to loop
  loop
    -- fetch one record into v_vc_id 
    fetch cur_card_numbers into v_card_number;
    exit when cur_card_numbers%notfound;
    --dbms_output.put_line('v_card_number:' || v_card_number);
    --a.backup one record to voucher_card_old
    insert into voucher_card_old select *  from voucher_card vc where vc.card_number = v_card_number;
    --b.delete one record from voucher_card
    delete from voucher_card vc where  vc.card_number = v_card_number;
    --a.backup one record to gm_goods_inst_old
    insert into gm_goods_inst_old select *  from gm_goods_inst ggi where ggi.goods_sn = v_card_number;
    --b.delete one record from gm_goods_inst
    delete from gm_goods_inst ggi where ggi.goods_sn = v_card_number;
    --d.insert into inventory_clear_record for tracking deleted data
    execute immediate 'insert into inventory_clear_record(card_number,create_time) values(:a,:b)' using v_card_number ,sysdate ;
    --dbms_output.put_line('rowcount:' || cur_card_numbers%rowcount);
    -- 1000 once ,commit
    if  mod(cur_card_numbers%rowcount,1000) = 0  then 
      commit;
      --dbms_output.put_line('batch commit:' || cur_card_numbers%rowcount);  
    end if ;
  end loop;
  --close cursor
  if cur_card_numbers%isopen then
    close cur_card_numbers;
  end if;
   commit;
  --excption 
exception
  when others then
    rollback;
end Proc_Clean_Inventory_Data;

数据量较少

如果数据量较少,可以直接将数据加载到游标中,分多次执行。

create or replace procedure Proc_Clean_Inventory_Data
authid current_user  is
  v_card_number voucher_card.card_number%type;
  v_inventory_clean_record_num number(3);
  v_createRecordTableSql  varchar2(1000);
  -- cusrosr card_number collection   
  cursor cur_card_numbers is 
      select card_number 
         from voucher_card vc
      where vc.card_number in
       (select goods_sn
          from gm_goods_inst
         where GOODS_TYPE_ID = 'V'
           and GOODS_STATE = 'C'
           and state_date < sysdate - 50)
          --and rownum <= 100000  
           ;
begin
   v_createRecordTableSql :='create table inventory_clear_record(card_number VARCHAR2(60),create_time DATE)'; 
  -- check exists or not 
  select count(1) into v_inventory_clean_record_num  from user_tables ut where ut.TABLE_NAME = 'INVENTORY_CLEAR_RECORD';
  -- create inventory_clear_record for once
  if v_inventory_clean_record_num = 0 then 
    execute immediate v_createRecordTableSql ;
  end if ; 
  /******Clean expired Data in voucher_card And gm_goods_inst******/
  --open cur_card_numbers,execute the cursor define sql
  open cur_card_numbers;
  --begin to loop
  loop
    -- fetch one record into v_vc_id 
    fetch cur_card_numbers into v_card_number;
    exit when cur_card_numbers%notfound;
    --dbms_output.put_line('v_card_number:' || v_card_number);
    --a.backup one record to voucher_card_old
    insert into voucher_card_old select *  from voucher_card vc where vc.card_number = v_card_number;
    --b.delete one record from voucher_card
    delete from voucher_card vc where  vc.card_number = v_card_number;
    --a.backup one record to gm_goods_inst_old
    insert into gm_goods_inst_old select *  from gm_goods_inst ggi where ggi.goods_sn = v_card_number;
    --b.delete one record from gm_goods_inst
    delete from gm_goods_inst ggi where ggi.goods_sn = v_card_number;
    --d.insert into inventory_clear_record for tracking deleted data
    execute immediate 'insert into inventory_clear_record(card_number,create_time) values(:a,:b)' using v_card_number ,sysdate ;
    --dbms_output.put_line('rowcount:' || cur_card_numbers%rowcount);
    -- 1000 once ,commit
    if  mod(cur_card_numbers%rowcount,1000) = 0  then 
      commit;
      --dbms_output.put_line('batch commit:' || cur_card_numbers%rowcount);  
    end if ; 
  end loop;
  --close cursor
  if cur_card_numbers%isopen then
    close cur_card_numbers;
  end if;
  commit;
  --excption 
exception
  when others then
    rollback;
end Proc_Clean_Inventory_Data;


配置Job ,定时执行

begin
  sys.dbms_job.submit(job => :job,
                      what => 'proc_clean_inventory_data;',
                      next_date => to_date('09-05-2018 02:00:00', 'dd-mm-yyyy hh24:mi:ss'),
                      interval => 'TRUNC(sysdate+1)+2/24');
  commit;
end;
/


定期进行表分析

我们这两个表是分区表,表分析SQL如下,主要是 GRANULARITY

BEGIN                                
 DBMS_STATS.GATHER_TABLE_STATS(OWNNAME          => 'CRM',
                                   TABNAME          => 'GM_GOODS_INST',
                                   ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE,
                                   METHOD_OPT       => 'for all columns size repeat',
                                   DEGREE           => 4,
                                   GRANULARITY      => 'ALL',
                                   CASCADE          => TRUE,
                                   no_invalidate    => false);
  END;                                 
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(OWNNAME          => 'CRM',
                                TABNAME          => 'VOUCHER_CARD',
                                ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE,
                                METHOD_OPT       => 'for all columns size repeat',
                                DEGREE           => 4,
                                GRANULARITY      => 'ALL',
                                CASCADE          => TRUE,
                                no_invalidate    => false);
END;


相关文章
|
7月前
|
SQL 安全 关系型数据库
【MySQL实战笔记】03.事务隔离:为什么你改了我还看不见?-01
【4月更文挑战第6天】MySQL事务的隔离性确保数据操作的完整性和一致性,ACID原则包括原子性、一致性、隔离性和持久性。事务隔离级别有四种:读未提交、读提交、可重复读和串行化,分别解决并发问题如脏读、不可重复读和幻读。不同隔离级别在效率和安全性间权衡,例如读未提交允许未提交变更可见,而串行化通过锁保证安全但可能降低效率。在不同隔离级别下,事务看到的数据状态会有所变化,例如在可重复读级别,事务始终看到初始数据,而在串行化级别,事务会等待其他事务完成再继续,避免数据冲突。
312 10
|
2月前
|
SQL 关系型数据库 MySQL
美团面试:mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)
本文详细解析了MySQL索引失效的多种场景及解决方法,包括破坏最左匹配原则、索引覆盖原则、前缀匹配原则、`ORDER BY`排序不当、`OR`关键字使用不当、索引列上有计算或函数、使用`NOT IN`和`NOT EXISTS`不当、列的比对等。通过实例演示和`EXPLAIN`命令分析,帮助读者深入理解索引失效的原因,并提供相应的优化建议。文章还推荐了《尼恩Java面试宝典》等资源,助力面试者提升技术水平,顺利通过面试。
|
7月前
|
存储 SQL 关系型数据库
【MySQL实战笔记】03.事务隔离:为什么你改了我还看不见?-02
【4月更文挑战第7天】数据库通过视图实现事务隔离,不同隔离级别如读未提交、读已提交、可重复读和串行化采用不同策略。以可重复读为例,MySQL使用多版本并发控制(MVCC),每个事务有其独立的视图。回滚日志在无更早视图时被删除。长事务可能导致大量存储占用,应避免。事务启动可显式用`begin`或设置`autocommit=0`,但后者可能意外开启长事务。建议使用`autocommit=1`并显式管理事务,若需减少交互,可使用`commit work and chain`。
51 5
|
7月前
|
存储 SQL 关系型数据库
【MySql】MySQL索引15连问(相信大家看完肯定会有帮助)
【MySql】MySQL索引15连问(相信大家看完肯定会有帮助)
96 0
【MySql】MySQL索引15连问(相信大家看完肯定会有帮助)
|
7月前
|
SQL 缓存 关系型数据库
Mysql调优你不知道这几点,就太可惜了
Mysql调优你不知道这几点,就太可惜了
125 0
|
存储 SQL 关系型数据库
为了让你彻底弄懂 MySQL 事务日志,我通宵赶出了这份图解!
在当今社会,充斥着大量的数据。从众多APP上的账户资料到银行信用体系等个人档案,都离不开对大量数据的组织、存储和管理。而这,便是数据库存在的目的和价值。本文将为大家详细讲解 MySQL 事务日志的相关知识。
4491 0
为了让你彻底弄懂 MySQL 事务日志,我通宵赶出了这份图解!
|
存储 Oracle 关系型数据库
面试官:从 MySQL 读取 100w 数据进行处理,应该怎么做?问倒一大遍!
面试官:从 MySQL 读取 100w 数据进行处理,应该怎么做?问倒一大遍!
550 0
|
存储 SQL 关系型数据库
63. 谈谈MySQL 索引,B+树原理,以及建索引的几大原则(MySQL面试第六弹)
63. 谈谈MySQL 索引,B+树原理,以及建索引的几大原则(MySQL面试第六弹)
142 0
63. 谈谈MySQL 索引,B+树原理,以及建索引的几大原则(MySQL面试第六弹)
|
存储 关系型数据库 MySQL
58. 盘点那些面试中最常问的MySQL问题,第一弹
58. 盘点那些面试中最常问的MySQL问题,第一弹
115 0
|
关系型数据库 MySQL 测试技术
软件测试mysql面试题:什么情况下不宜建立索引?
软件测试mysql面试题:什么情况下不宜建立索引?
122 0
下一篇
DataWorks