Загрузка данных в огромную секционированную таблицу - PullRequest
4 голосов
/ 24 августа 2010

У меня огромный стол. Сначала диапазон разделен на price_date, затем хэш разделен на fund_id. Таблица имеет 430 миллионов строк. Каждый день у меня есть пакетное задание, в которое вставляется от 1,5 до 3 миллионов строк каждый день.

Мы ищем для включения и выключения локальные индексы (не все индексы, но основанные на данных, разделы которых касаются только данные)

Есть ли у кого-нибудь опыт ускорения вставки в большой стол без использования метода перетаскивания и восстановления?

У кого-нибудь есть предложения только для этой ситуации?

Ответы [ 2 ]

4 голосов
/ 24 августа 2010

Иди, прочти это:

http://www.evdbt.com/TGorman%20TD2005%20DWScale.doc

Это работает.

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

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

Моя таблица это диапазон / список, а не диапазон / хэш. поэтому вам придется изменить его, возможно, с помощью функции ORA_HASH, чтобы найти нужные подразделы. Я также записываю в таблицу, какие подразделы я собираюсь пометить как непригодные для использования, поэтому я могу сделать все это за один проход. Может быть несколько эффективнее пометить все индексы подраздела как непригодные для использования в одной инструкции ALTER TABLE; Первоначально я только отключал индексы BITMAP, но даже когда автономные индексы дерева B * отключались во время загрузки данных, значительно повысили эффективность.

  procedure DISABLE_LOCAL_INDEXES as
     l_part_name varchar2(30);
     l_subpart_name varchar2(30);
     l_sql varchar2(2000);
     type partition_rec_type is record
     (table_name         varchar2(30),
      partition_name     varchar2(30),
      subpartition_name  varchar2(30),
      list_value         varchar2(10),
      min_ts             timestamp,
      max_ts             timestamp);
     type partition_recs_type
                         is table of partition_rec_type;
     l_partition_recs    partition_recs_type := partition_recs_type();
     l_partition_rec     partition_rec_type;
     l_subpart_id        number := 1;
     l_start_ts          timestamp;
     l_end_ts            timestamp;
     l_found_list_part boolean;
   begin
     -- build set of subpartitions
     l_start_ts := to_timestamp ('1970-01-01', 'yyyy-mm-dd');
     for i in (select p.table_name, p.partition_name, sp.subpartition_name,
                      p.high_value as part_high_value, 
                      sp.high_value as subpart_high_value,
                      p.partition_position, sp.subpartition_position
                 from user_tab_subpartitions sp
                      inner join user_tab_partitions p
                         on p.table_name     = sp.table_name
                        and p.partition_name = sp.partition_name
                where p.table_name = 'MY_TARGET_TABLE'
                order by p.partition_position, sp.subpartition_position)
     loop
       if ( (i.partition_position <> 1) and (i.subpartition_position = 1) ) then
         l_start_ts    := l_end_ts + to_dsinterval('0 00:00:00.000000001');
       end if;
       if (i.subpartition_position = 1) then
         l_end_ts := high_val_to_ts (i.part_high_value);
         l_end_ts := l_end_ts - to_dsinterval('0 00:00:00.000000001');
       end if;
       l_partition_rec.table_name        := i.table_name;
       l_partition_rec.partition_name    := i.partition_name;
       l_partition_rec.subpartition_name := i.subpartition_name;
       l_partition_rec.list_value        := i.subpart_high_value;
       l_partition_rec.min_ts            := l_start_ts;
       l_partition_rec.max_ts            := l_end_ts;
       l_partition_recs.extend();
       l_partition_recs(l_subpart_id) := l_partition_rec;
       l_subpart_id := l_subpart_id + 1;
     end loop;
     -- for every combination of list column and date column
     -- which is going to be pushed to MY_TARGET_TABLE
     -- find the subpartition
     -- otherwise find the partition and default subpartition
     for i in (select distinct LIST_COLUMN, DATE_COLUMN as DATE_VALUE
                 from MY_SOURCE_TABLE
                where IT_IS_BEING_MOVED_TO_TARGET IS TRUE)
     loop
       -- iterate over the partitions
       l_found_list_part := false;
       for k in l_partition_recs.first..l_partition_recs.last
       loop
         -- find the right partition / subpartition for list_value / date_value
         if (    (i.DATE_VALUE >= l_partition_recs(k).min_ts)
             and (i.DATE_VALUE <= l_partition_recs(k).max_ts) ) then
           if (l_found_list_value = false) then
             if (to_char(i.LIST_COLUMN, '9999') = l_partition_recs(k).LIST_COLUMN) then
               l_found_list_value := true;
             elsif (l_partition_recs(k).LIST_COLUMN = 'DEFAULT') then
               l_partition_rec := l_partition_recs(k);
             end if;
           end if;
         end if;
       end loop;  -- over l_partition_recs
       -- log those partitions for later index rebuild
       begin
         insert into index_subpart_rebuild
           (table_name, partition_name, subpartition_name)
         values
           (l_partition_rec.table_name, l_partition_rec.partition_name,
            l_partition_rec.subpartition_name);
       exception
         when dup_val_on_index then null;
         when others then raise;
       end;
     end loop;  -- over MY_TARGET_TABLE.DATE_VALUE values
     commit;
     for i in (select ui.index_name, uis.subpartition_name
                 from user_indexes ui
                      inner join user_ind_subpartitions uis
                         on ui.index_name = uis.index_name
                      inner join index_subpart_rebuild re
                         on re.subpartition_name = uis.subpartition_name
                where ui.table_name = 'MY_TARGET_TABLE')
     loop
       l_sql := 'alter index ' || i.index_name ||
                ' modify subpartition ' || i.subpartition_name || ' unusable';
       execute immediate l_sql;
     end loop;
   end DISABLE_LOCAL_INDEXES;
0 голосов
/ 16 декабря 2010

Я не уверен, какую базу данных вы используете,

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

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

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