Зафиксируйте каждые 1000 строк

Я пытаюсь сделать коммит каждые 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: снимок слишком старый: сегмент отката с номером%n с именем "%segname" слишком мал.

3 ответа

Это звучит идеально для массового сбора!

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;
/

Вы можете сделать ваше табличное пространство отмены достаточно большим, чтобы все изменения данных в исходном операторе удаления могли быть сохранены в отмене. Затем вы можете увеличить параметр undo_retention, чтобы он длился дольше, чем требуется для выполнения вашего исходного оператора удаления. Таким образом, если для удаления требуется 1 час, установите для сохранения отмены 4 часа и продолжайте увеличивать размер табличного пространства отмены, пока вы не получите ORA-01555 при запуске удаления. 1 миллион строк не так много, чтобы удалить, если строки не очень большие. Вы должны быть в состоянии предотвратить ORA-01555 с помощью отмены.

Бобби

Спасибо всем. Мы решили пойти по этому пути после разговора с администратором базы данных>

Другие вопросы по тегам