2016-09-23 6 views
0

Мне нужно обновить таблицу, содержащую несколько миллионов строк. Обновление довольно простое, но поскольку оно изменит миллионы записей, интересно, какое наилучшее решение:Простое обновление Oracle или небольшое обновление пакета?

  • Выполните одно большое обновление.
  • Обновите таблицу и зафиксируйте изменения в небольших партиях, используя команды bulk collect/forall.

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

Итак, какое решение лучше?

Спасибо,

+4

[комментарий Тома Кайта на частые фиксаций] (https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4951966319022): «* является неправильно, неправильно, так неправильно .... Так очень очень неправильно * "или" * Часто совершать ... делает это для вас: замедляет вас, да, это правильно, МЕДАЕТ ВАС ВНИЗ * " –

+0

Имеет смысл, Теперь у меня есть хорошие аргументы, чтобы придерживаться моего решения. Благодарю. – DoubleT28

+1

У IIRC некоторые огромные обновления имеют проблемы с сегментами отката («ORA-01555: снимок слишком старый»), поэтому рекомендуется иногда обновлять поблочно. –

ответ

0

Программы, которые проводят много вставных обработки времени, UPDATE или DELETE заявления, или Перебор результатов запроса. Вам нужно будет изучить инструкцию FORALL для выпуска DML, а BULK COLLECT INTO и RETURNING BULK COLLECT INTO в предложениях для запросов. Вы можете проверить этот документ для своей цели. http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm

И ответ здесь для вашей ситуации.

https://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:6407993912330

+0

В то время как 'bulk collect' и' forall' являются ценными, обычно лучше выполнять пакетные обновления. Даже если вы не можете сразу обновить всю таблицу. – pohart

0

Если дб имеет простои, самое быстрое решение, вероятно, сделать, как Tom Kyte говорит:

create table new as select ... from old; 
drop table old; 
rename table new to old; 

Если у вас нет окна, где это может произойти (это, вероятно, заказы на величину быстрее) и блокировка таблицы не допускается, тогда я рекомендую вам проверить dbms_parallel_execute. Oracle может разделить таблицу на куски и обновить каждый кусок отдельно. Это намного чище, чем насыпной сбор и обновление FORALL, потому что вы можете просто использовать оператор обновления вы бы иметь, если вы хотите один большое обновления с дополнительным условием and rowid between :start and :stop

begin 
    dbms_parallel_execute.create_task (task_name => 'MyTask'); 
    dbms_parallel_execute.create_chunks_by_rowid(
     task_name => 'MyTask', 
     table_owner => 'Me', 
     table_name => 'MyTable', 
     by_row  => true, 
     chunk_size => 1000); 
    dbms_parallel_execute.run_task(
     task_name  => 'MyTask', 
     sql_stmt  => 'UPDATE mytable 
          set col = newval 
          where ... 
          and rowid between :start_id and :end_id', 
     language_flag => dbms_sql.native, 
     parallel_level => 8); 

тогда, когда это будет сделано проверить состояние:

dbms_parallel_execute.task_status(task_name => 'MyTask') = dbms_parallel_execute.FINISHED 

и отбросить задачу, если она преуспела.

dbms_parallel_execute.drop_task(task_name => 'MyTask');