日期:2014-05-16  浏览次数:20455 次

一亿行删除或修改一千万行的思路总结续

       接着上一篇文章:

                            一亿行删除或修改一千万行的思路     

       思路二: CTAS + RENAME
      
       因为要在对数据库及其他应用影响最小的情况下做
       如果直接对表进行删除则会出现应用因为等待数据释放锁而等待
       而且常规的DELETE语句,会生成大量的UNDO和REDO
       而且表上如果有大量索引的话,导致删除还会更慢
       而且可能会造成大量的空数据块,如果有扫描大量行的操作,空块太多,也会导致性能下降
      
       如果可以停止业务,防止对此表的更新
       那么CTAS + RENAME也是个不赖的选择
       这种方法只适用于没有业务发生的情况,对于大多数OLTP系统还是不适用的
       由于CTAS是DDL语句,基本没有太多UNDO的生成,如果CTAS失败了,重新在执行一遍即可
      
       大致过程如下
           比如:对象表为test_01,我想要删去日期(deal_date)为20120301的数据
          
            ① CTAS的方法创建一个新表,建表条件为删除条件的对立条件,可考虑nologging+并行
               例如:create table test_02 as select * from test_01 where deal_Date<>'20120301'
              
            ② 在新表上建立相关索引和约束
           
            ③ 重命名新表为老表名字
               例如:ALTER TABLE test_02 RENAME TO test_01
              
            ④ 如果没问题 删除老表
           
            ⑤ 最后查看和该表相关的存储过程、函数等,重新编译
          
       如果用CTAS在建表的时候会对原表建立一致性读的
       如果这时候对原表有插入或更新,就需要访问undo表空间然后完成一致读
       而且一旦失败需要全部回滚,数据量这么大,这样做的风险是巨大的
       我们可以访问dba_extents视图,通过rowid将原表划分成许多不重叠的区域
       然后起多个job,job中通过rowid访问然后删除数据
       删除完后的区域写日志,这样即使中途失败通过划分的rowid区域和日志都是可以重启的
       而且速度要比bulkcollect好,因为bulk collect是缓存100到200条一delete,一个区域直接一个delete
       但是这种方式最好需要先在表上加读取锁,不然有insert和update会破坏原来的rowid划分
      
       这种通过rowid的思路,我会在下一篇博客继续介绍
      
       未完待续.....