Эффективный способ обновить все строки в таблице - PullRequest
34 голосов
/ 14 апреля 2010

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

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

Каков наиболее эффективный способ сделать это в SQL без использования некоторых специфических для диалекта функций, поэтому он работает везде (Oracle, MSSQL, MySQL, PostGre и т. Д.)?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Рассчитанные поля отсутствуют. Есть индексы. Используются сгенерированные операторы SQL, которые обновляют таблицу построчно.

Ответы [ 6 ]

52 голосов
/ 14 апреля 2010

Обычный способ - использовать ОБНОВЛЕНИЕ:

UPDATE mytable
   SET new_column = <expr containing old_column>

Вы должны быть в состоянии сделать это за одну транзакцию.

8 голосов
/ 15 апреля 2010

Как Марсело предлагает:

UPDATE mytable
SET new_column = <expr containing old_column>;

Если это занимает слишком много времени и завершается неудачно из-за ошибок «снимок слишком старый» (например, если выражение запрашивает другую высокоактивную таблицу), и если новое значение для столбца всегда равно NULL, вы можете обновить таблицу партии:

UPDATE mytable
SET new_column = <expr containing old_column>
WHERE new_column IS NULL
AND ROWNUM <= 100000;

Просто запустите это утверждение, COMMIT, а затем запустите его снова; промыть, повторять, пока не появится сообщение «0 строк обновлено». Это займет больше времени, но каждое обновление с меньшей вероятностью завершится ошибкой.

EDIT:

Лучшей альтернативой, которая должна быть более эффективной, является использование DBMS_PARALLEL_EXECUTE API.

Пример кода (из документации Oracle):

DECLARE
  l_sql_stmt VARCHAR2(1000);
  l_try NUMBER;
  l_status NUMBER;
BEGIN

  -- Create the TASK
  DBMS_PARALLEL_EXECUTE.CREATE_TASK ('mytask');

  -- Chunk the table by ROWID
  DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID('mytask', 'HR', 'EMPLOYEES', true, 100);

  -- Execute the DML in parallel
  l_sql_stmt := 'update EMPLOYEES e 
      SET e.salary = e.salary + 10
      WHERE rowid BETWEEN :start_id AND :end_id';
  DBMS_PARALLEL_EXECUTE.RUN_TASK('mytask', l_sql_stmt, DBMS_SQL.NATIVE,
                                 parallel_level => 10);

  -- If there is an error, RESUME it for at most 2 times.
  l_try := 0;
  l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS('mytask');
  WHILE(l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED) 
  LOOP
    l_try := l_try + 1;
    DBMS_PARALLEL_EXECUTE.RESUME_TASK('mytask');
    l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS('mytask');
  END LOOP;

  -- Done with processing; drop the task
  DBMS_PARALLEL_EXECUTE.DROP_TASK('mytask');

END;
/

Документы Oracle: https://docs.oracle.com/database/121/ARPLS/d_parallel_ex.htm#ARPLS67333

2 голосов
/ 14 апреля 2010

Вы можете удалить любые индексы в таблице, затем выполнить вставку, а затем заново создать индексы.

0 голосов
/ 22 августа 2018

обновление Отели, в которых установлена ​​скидка = 30, где Hotelid> = 1 и Hotelid <= 5504 </p>

0 голосов
/ 19 апреля 2010

Какая версия базы данных? Проверьте виртуальные столбцы в 11g:

Добавление столбцов со значением по умолчанию http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/11g-schemamanagement.html

0 голосов
/ 14 апреля 2010

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

создан updated_ {table_name}, затем выберите вставку в эту таблицу в пакетном режиме. После завершения, и это зависит от Oracle (который я не знаю или не использую), поддерживающего возможность переименования таблиц атомарным способом. updated_ {table_name} становится {table_name}, а {table_name} становится original_ {table_name}.

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

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