【问题标题】:Commit every 1000 rows每 1000 行提交一次
【发布时间】:2018-07-03 10:29:25
【问题描述】:

我希望每 1000 行提交一次,直到所有记录都被删除,我们有超过一百万条记录要删除。

原来:

private static final String DELETE_OLD_REPORTS_FROM_REPORTING =
-            "DELETE FROM A_REPORTING\n" +
-            "WHERE ID IN(" +
-            "SELECT ID FROM A_REPORTING\n" +
-            "WHERE STATUS = 'LOADED'\n" +
-            "AND CREATE_DT < TO_DATE(:createdDate, 'dd-mon-yyyy'))";

我正在考虑做这样的事情:

"BEGIN\n" +
                "LOOP\n" +
                    "DELETE FROM A_REPORTING\n" +
                    "WHERE ID IN(" +
                    "SELECT ID FROM A_REPORTING\n" +
                    "WHERE STATUS = 'LOADED'\n" +
                    "AND CREATE_DT < TO_DATE(:createdDate, 'dd-mon-yyyy')\n+" +
                    "AND ROWNUM <= 10000);\n" +
                    "EXIT WHEN SQL%rowcount < 9999;\n" +
                    "COMMIT;\n" +
                "END LOOP;\n"+
            "COMMIT;\n" +
            "END";

但是,有没有更好的方法来做到这一点?这是因为我们收到了 ORA-01555 错误:

ORA-01555:快照太旧:名称为“%segname”的回滚段号 %n 太小。

【问题讨论】:

  • 您可以将条件从子查询中提取到IN 并将它们直接添加到外部查询中(从而完全摆脱IN)。也许不相关,但也可能渗入查询。你有STATUSCREATE_DT 的索引吗?这也可能会加快速度。
  • 你有 Oralce DB - 对吧?为什么不能在数据库本身中执行删除逻辑?
  • 删除一百万行后,表中会有多少行?
  • @sticky bit - 他不能直接在 DELETE 中添加 ROWNUM 过滤器,他添加了子查询来绕过它,并且 STATUS/CREATE_DT 上的过滤必须伴随 ROWNUM。跨度>
  • @GaryMyers:我的意思是第一个没有ROWNUM 的查询。但是IN 可以被消除并可能加快查询速度(并且可能足够快以消除对“提交每 n 条记录”杂技的需要)。

标签: sql oracle sql-delete ora-01555


【解决方案1】:

这听起来很适合批量收集!

declare

  d_created_date   date   := to_date(:createddate, 'dd-mon-yyyy'); -- define :createddate here

  -- get all rows you want to delete
  cursor cur_delete_records is
  select r.rowid 
    from a_reporting r
   where r.status = 'LOADED'
     and r.create_dt < to_date(d_created_date, 'dd-mon-yyyy');

  -- collection to store rows
  type t_delete_records   is table of cur_delete_records%rowtype;
  rec_delete_records      t_delete_records;

begin

  open cur_delete_records;
    loop
      fetch cur_delete_records
      bulk collect into rec_delete_records
      limit 1000; -- here's the 1,000 record max per loop
      exit when nvl(rec_delete_records.count, 0) = 0;

      forall x in rec_delete_records.first .. rec_delete_records.last

        delete from a_reporting r
         where r.rowid = rec_delete_records(x).rowid;

        commit;

    end loop;
  close cur_delete_records;

end;
/

【讨论】:

    【解决方案2】:

    您可以使您的撤消表空间足够大,以便原始删除语句的所有数据更改都可以保留在撤消中。然后,您可以增加您的 undo_retention 参数,使其比原来的删除语句运行所需的时间更长。因此,如果删除需要 1 小时运行,则将撤消保留设置为 4 小时并不断增加撤消表空间的大小,直到在运行删除时没有得到 ORA-01555。除非行非常大,否则删除 100 万行并不算多。您应该能够通过撤消来防止 ORA-01555。

    鲍比

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      相关资源
      最近更新 更多