2014-03-16 2 views
0

Мне нужен ваш совет для моего нижнего регистра.Oracle: после вставки в выбрать, обновить таблицу

  1. получить данные из maintable и вставить в DataTable, где ROWNUM < = некоторое значение

  2. когда все данные уже вставить в DataTable, я хочу эти данные в maintable обновит STAUS.

Проблема в том, что rownum более 500 тыс., Это занимает около 10 минут. На этот раз может возникнуть еще один запрос - получить одни и те же данные. Как я хочу это предотвратить?

Ниже мой sql.

insert into dataTable(id,num,status) select m.id,m.num,m.status from mainTable m where m.status = 'FREE' and rownum <= 100000; 

update mainTable m set m.status = 'RESERVED' where m.num in (select d.num from dataTable where d.status = 'FREE'); 

я сделать некоторые исследования, но я не знаю, нужен ли я использовать оператор select for update или merge?

+0

Это два отдельных запроса, не связанных между собой, потому что вы не вставляете столбец STATUS в 'dataTable'. Вы уверены, что это то, что вы хотите делать? Если он «медленный», вероятно, из-за отсутствия индексов/избирательности в столбце STATUS в 'dataTable' или NUM в' mainTable'. Можете ли вы указать количество записей, избирательность в каждом и план объяснения для этих запросов? – Ben

+0

«вы не вставляете СТАТУС» - некоторая ошибка, я просто редактирую свой sql. Я также включаю статус. «Если это« медленно », это, вероятно, связано с отсутствием индексов/избирательности в столбце« - для dataTable нет индекса. Но для mainTable id, num и status имеют индекс. Я считаю, что если таблица имеет индекс, это замедлит вставку. – Sh4m

+0

mainTable содержит 50 миллионов записей. – Sh4m

ответ

1

Вы не можете использовать MERGE, как вы можете только вставить или обновить целевой таблицы. Я предполагаю, что проблема заключается либо в селективности столбца STATUS в dataTable, либо в столбце NUM в mainTable.

В любом случае, если вы только хотите, чтобы обновить эти строки в mainTable, что вы только что вставленные в mainTable самое простое, что нужно сделать было бы вспомнить, что вы только что вставили и обновлять это. BULK COLLECT кажется уместным.

declare 

    cursor c_all is 
    select rowid as rid, id, num, status 
     from maintable 
     where status = 'FREE' 
     and rownum <= 100000; 

    type t__all is table of c_all%rowtype index by binary_integer; 
    t_all t__all; 

begin 

    open c_all; 
    loop 
     fetch c_all bulk collect into t_all limit 10000; 

     forall i in t_all.first .. t_all.last 
     insert into datatable (id, num, status) 
     values (t_all(i).id, t_all(i).num, t_all(i.status)); 

     forall i in t_all.first .. t_all.last 
     update maintable 
      set status = 'RESERVED' 
      where rowid t_all(i).rid; 

    end loop; 
    commit; 
    close c_all; 

end; 
/

Это не эквивалентно запрос, он предполагает, что maintable уникален по NUM. Если это уникальный по ID я бы изменить UPDATE к MERGE (это уборщик) и удалить столбец ROWID из курсора:

forall i in t_all.first .. t_all.last 
    merge into maintable m 
    using (select t_all(i).num from dual) d 
     on (m.num = d.num) 
    when matched then 
     update 
      set m.status = 'RESERVED' 

Как я уже писал, хотя, если проблема избирательность столбцов/индексирование вам нужно опубликовать план объяснения, индексы и т. д.

+0

Привет, Бен, я попробовал эту сборку, это очень быстро. И я также добавил некоторый индекс в dataTable. благодаря – Sh4m

0

Я думаю, что лучше использовать EXISTS обмен с использованием in в запросе обновления, это так быстрее:

update mainTable m 
set m.status = 'RESERVED' 
where exists (select * from dataTable where m.num = d.num and d.status = 'FREE'); 
+0

Фактически первый запрос занимал некоторое время. Около 10 минут. – Sh4m

Смежные вопросы