Как ОБНОВИТЬ большую таблицу в oracle pl / sql партиями, чтобы избежать исчерпания пространства? - PullRequest
3 голосов
/ 22 августа 2010

У меня очень большая таблица (5 мм записей).Я пытаюсь запутать столбцы VARCHAR2 таблицы случайными буквенно-цифровыми цифрами для каждой записи в таблице.Моя процедура успешно выполняется на меньших наборах данных, но в конечном итоге она будет использоваться на удаленной базе данных, настройками которой я не могу управлять, поэтому я бы хотел выполнить инструкцию UPDATE в пакетах, чтобы избежать исчерпания пространства.

Есть ли какая-либо опция, которую я могу включить, или стандартный способ обновления в блоках?

Я добавлю, что не будет никаких отличительных особенностей записей, которые не был запутан, поэтому моя единственная мысль об использовании rownum в цикле не сработает (я думаю).

Ответы [ 4 ]

5 голосов
/ 23 августа 2010

Если вы собираетесь обновить каждую строку в таблице, вам лучше сделать Create Table As Select, затем отбросить / усечь исходную таблицу и повторно добавить новые данные. Если у вас есть опция разделения, вы можете создать новую таблицу как таблицу с одним разделом и просто поменять ее местами с помощью EXCHANGE PARTITION.

Для вставок требуется гораздо меньше отмен, а прямая вставка с добавлением nologging (/ + APPEND / подсказка) также не вызовет большого повторения.

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

2 голосов
/ 23 августа 2010

Следующее не проверено, но должно работать:

declare
  l_fetchsize number := 10000;
  cursor cur_getrows is
  select rowid, random_function(my_column)
    from my_table;

  type rowid_tbl_type      is table of urowid;
  type my_column_tbl_type  is table of my_table.my_column%type;

  rowid_tbl     rowid_tbl_type;
  my_column_tbl my_column_tbl_type;
begin

  open cur_getrows;
  loop
    fetch cur_getrows bulk collect  
      into rowid_tbl, my_column_tbl 
      limit l_fetchsize;
    exit when rowid_tbl.count = 0;

    forall i in rowid_tbl.first..rowid_tbl.last
      update my_table 
         set my_column = my_column_tbl(i)
       where rowid     = rowid_tbl(i);
    commit;
  end loop;
  close cur_getrows;
end;
/

Это неоптимально эффективно - одно обновление будет - но оно будет делать меньшие, настраиваемые пользователем пакеты, используя ROWID.

0 голосов
/ 03 января 2013

Если бы мне пришлось обновлять миллионы записей, я бы, вероятно, выбрал НЕ обновлять.

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

CREATE TABLE new_table as select <do the update "here"> from old_table;

index new_table
grant on new table
add constraints on new_table
etc on new_table

drop table old_table
rename new_table to old_table;

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

0 голосов
/ 23 августа 2010

Я делаю это путем сопоставления первичного ключа с целым числом (mod n), а затем выполняю обновление для каждого x, где 0 <= x <n. </p>

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

UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=0
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=1
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=2

У вас может быть больше разделов, и вы можете захотеть поместить это в цикл (с некоторыми коммитами).

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