Быстрое обновление базы данных с более чем 10 миллионами записей - PullRequest
1 голос
/ 14 февраля 2012

Я довольно новичок в SQL, и мне было интересно, может ли кто-нибудь мне помочь.

У меня есть база данных, которая содержит около 10 миллионов строк.

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

Проблема, с которой я сталкиваюсь при выполнении простого оператора обновления, заключается в том, что он сместит пространство отката.

Я былчитая вокруг, что мне нужно использовать BULK COLLECT AND FETCH.

Моя идея состояла в том, чтобы извлекать 10 000 записей одновременно, обновлять, фиксировать и продолжать извлекать.

Я пытался искать примеры в Googleно я еще ничего не нашел.

Любая помощь?

Спасибо !!

Это то, что у меня есть:

DECLARE
    CURSOR rec_cur IS
    SELECT DATE_ORIGIN 
    FROM MAIN_TBL WHERE DATE_ORIGIN IS NULL;

    TYPE date_tab_t IS TABLE OF DATE;

    date_tab date_tab_t;

BEGIN
    OPEN rec_cur;
    LOOP
        FETCH rec_cur BULK COLLECT INTO date_tab LIMIT 1000;
        EXIT WHEN date_tab.COUNT() = 0;

        FORALL i IN 1 .. date_tab.COUNT
            UPDATE MAIN_TBL SET DATE_ORIGIN  = '23-JAN-2012' 
            WHERE DATE_ORIGIN IS NULL;

    END LOOP;
    CLOSE rec_cur;
END;

1 Ответ

3 голосов
/ 15 февраля 2012

Мне кажется, я вижу, что ты пытаешься сделать.Я хочу высказать несколько замечаний относительно различий между приведенным ниже кодом и вашим.

  1. Ваш forall цикл не будет использовать индекс.Это легко обойти, используя rowid для обновления вашей таблицы.
  2. Подтверждая после каждого forall, вы уменьшаете количество необходимых отмен;но затруднить откат, если что-то пойдет не так.Хотя логически ваш запрос может быть легко перезапущен посередине и без ущерба для вашей цели.
  3. rowids малы, собирайте не менее 25 тыс. Одновременно;если не 100k.
  4. Вы не можете индексировать ноль в Oracle.На стеке есть много вопросов об этом, вам нужно больше информации.Функциональный индекс на что-то вроде nvl(date_origin,'x') в качестве свободного примера увеличит скорость, с которой вы выбираете данные.Это также означает, что вам никогда не придется использовать саму таблицу.Вы выбираете только из индекса.
  5. Ваш тип данных даты выглядит как строка.Я сохранил это, но это не разумно.
  6. Если вы можете заставить кого-то увеличить размер отменяемого табличного пространства, тогда обновление будет быстрее.

Предполагается, что согласно вашим комментариямdate_origin - это дата, тогда индекс должен быть примерно таким:

nvl(date_origin,to_date('absolute_minimum_date_in_Oracle_as_a_string','yyyymmdd'))

У меня нет доступа к БД в данный момент, но чтобы узнать amdiOaas, запустите следующий запрос:

select to_date('0001','yyyy') from dual;

Это должно вызвать полезную ошибку для вас.


Рабочий пример в PL / SQL Developer.

 create table main_tbl as
  select cast( null as date ) as date_origin
    from all_objects
         ;

create index i_main_tbl
   on main_tbl ( nvl( to_date(date_origin,'yyyy-mm-dd')
                    , to_date('0001-01-01' ,'yyyy-mm-dd') )
                )
      ;

declare

   cursor c_rec is
    select rowid
      from main_tbl
     where nvl(date_origin,to_date('0001-01-01','yyyy-mm-dd')) 
               = to_date('0001-01-01','yyyy-mm-dd')
          ;

   type t__rec is table of rowid index by binary_integer;
   t_rec t__rec;

begin

   open c_rec;
   loop

      fetch c_rec bulk collect into t_rec limit 50000;

      exit when t_rec.count = 0;

      forall i in t_rec.first .. t_rec.last
         update main_tbl
            set date_origin = to_date('23-JAN-2012','DD-MON-YYYY')
          where rowid = t_rec(i)
                ;
         commit ;

   end loop;
   close c_rec;
end;
/
...