как получить, удалить, зафиксировать от курсора - PullRequest
5 голосов
/ 22 апреля 2011

Я пытаюсь удалить много строк из таблицы. Я хочу попробовать метод помещения строк, которые я хочу удалить, в курсор, а затем продолжать извлекать, удалять, фиксировать каждую строку курсора, пока она не станет пустой.

В приведенном ниже коде мы являемся fetching строками и помещаем их в TYPE.

Как я могу изменить приведенный ниже код, чтобы удалить ТИП с картинки, и просто сделать fetch,delete,commit на самом курсоре.

    OPEN bulk_delete_dup;
    LOOP
        FETCH bulk_delete_dup BULK COLLECT INTO arr_inc_del LIMIT c_rows;

        FORALL i IN arr_inc_del.FIRST .. arr_inc_del.LAST
              DELETE FROM UIV_RESPONSE_INCOME 
              WHERE ROWID = arr_inc_del(i);

        COMMIT;
        arr_inc_del.DELETE;
        EXIT WHEN bulk_delete_dup%NOTFOUND;
    END LOOP;
    arr_inc_del.DELETE;
    CLOSE bulk_delete_dup;

Ответы [ 2 ]

17 голосов
/ 22 апреля 2011

Почему вы хотите совершать партии?Это только замедлит вашу обработку.Если нет других сеансов, которые пытаются изменить строки, которые вы пытаетесь удалить, что кажется проблематичным по другим причинам, наиболее эффективным подходом было бы просто удалить данные с помощью одного DELETE, то есть

DELETE FROM uiv_response_income uri
 WHERE EXISTS( 
    SELECT 1
      FROM (<<bulk_delete_dup query>>) bdd
     WHERE bdd.rowid = uri.rowid
  )

Конечно, вполне может быть более оптимальный способ написать это в зависимости от того, как устроен запрос за вашим курсором.

Если вы действительно хотите исключить BULK COLLECT (который существенно замедлит процесс)вы можете использовать синтаксис WHERE CURRENT OF для выполнения DELETE

SQL> create table foo
  2  as
  3  select level col1
  4    from dual
  5  connect by level < 10000;

Table created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10    end loop;
 11* end;
SQL> /

PL/SQL procedure successfully completed.

Однако учтите, что, поскольку вам нужно заблокировать строку (с помощью предложения FOR UPDATE), вы не можете поместить коммит впетля.Выполнение фиксации приведет к снятию блокировок, запрошенных вами с помощью FOR UPDATE, и вы получите ORA-01002: ошибка выборки из последовательности

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10      commit;
 11    end loop;
 12* end;
SQL> /
declare
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 7

Вы можете не получить ошибку времени выполнения, если уберете блокировкуи избегайте синтаксиса WHERE CURRENT OF, удаляя данные на основе значений, выбранных вами из курсора.Однако, это все еще делает выборку через фиксацию, что является плохой практикой и радикально увеличивает шансы, что вы, по крайней мере периодически, получите ошибку ORA-01555: снимок слишком старый.Он также будет мучительно медленным по сравнению с одним оператором SQL или параметром BULK COLLECT.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where col1 = l_rowtype.col1;
 10      commit;
 11    end loop;
 12* end;
SQL> /

PL/SQL procedure successfully completed.

Конечно, вы также должны убедиться, что ваш процесс перезапускается, если вы обрабатываете некоторое подмножество строк и имеетекакое-то неизвестное количество временных коммитов до того, как процесс умирает.Если DELETE достаточно, чтобы строка больше не возвращалась из вашего курсора, ваш процесс, вероятно, уже перезапускается.Но в целом это вызывает беспокойство, если вы пытаетесь разбить одну операцию на несколько транзакций.

1 голос
/ 26 апреля 2011

Несколько вещей.Судя по правилу вашей компании «нет транзакций за 8 секунд» (8 секунд, вы в Техасе?), У вас есть производственный экземпляр БД, который традиционно поддерживает приложения, выполняющие OLTP (вставка 1 строки, обновление 2 строки и т. Д.), И имееттеперь также становится базой данных пакетной обработки (удалите 50% строк и замените новыми строками 1 мм).

Пакетная обработка должна быть отделена от экземпляра OLTP.В экземпляре пакета («фабрика данных») я не пытался бы удалить в этом случае, я бы, вероятно, сделал CTAS, удалил старую таблицу, переименовал новую таблицу, перестроил индексы / статистику, перекомпилировал неверный подход objs.

Предполагая, что вы застряли, выполняя пакетную обработку в своем "8-секундном" экземпляре, вы, вероятно, обнаружите, что ваша компания будет запрашивать все больше и больше этого в будущем, поэтому попросите администраторов баз данных как можно больше откатить,и надеемся, что вы не получите слишком старый снимок при выборке по коммитам (курсор выбирает, удаляя, фиксирует каждые 1000 строк или около того, удаляет с помощью rowid).

Если администраторы базы данных не могут помочь, вы можете сначала создать временную таблицу, содержащую те строки, которые вы хотите удалить, а затем выполнить цикл по временной таблице, чтобы удалить ее из основной таблицы (избегая выборки между коммитами), ноВаша компания, вероятно, будет иметь какое-то правило против этого, так как это еще один (основной) пакетный метод.

Что-то вроде:

declare

-- assuming index on someCol
cursor sel_cur is
select rowid as row_id
from someTable
where someCol = 'BLAH';

v_ctr pls_integer := 0;
begin
for rec in sel_cur
loop
  v_ctr := v_ctr + 1;
  -- watch out for snapshot too old...
  delete from someTable
  where rowid = rec.row_id;
  if (mod(v_ctr, 1000) = 0) then
    commit;
  end if;
end loop;
commit;

end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...