Как оптимизировать SQL обновления, который выполняется в таблице Oracle с 700M строками - PullRequest
10 голосов
/ 03 июня 2010
UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL

[TABLE] - таблица базы данных Oracle с более чем 700 миллионами строк. Я отменил выполнение SQL после 6 часов работы.

Есть ли подсказка SQL, которая может улучшить производительность? Или любое другое решение, чтобы ускорить это?

РЕДАКТИРОВАТЬ: Этот запрос будет выполнен один раз, а затем никогда больше.

Ответы [ 5 ]

10 голосов
/ 03 июня 2010

Прежде всего, это разовый запрос или повторяющийся? Если вам нужно сделать это только один раз, возможно, вы захотите запустить запрос в параллельном режиме. В любом случае вам придется сканировать все строки, вы можете либо разделить рабочую нагрузку на диапазоны ROWID (параллелизм самостоятельно), либо использовать встроенные функции Oracle.

Предполагая, что вы хотите часто его запускать и хотите оптимизировать этот запрос, количество строк со столбцом field, равным NULL, в конечном итоге будет небольшим по сравнению с общим числом строк. В этом случае индекс может ускорить процесс. Oracle не индексирует строки, в которых все индексированные столбцы имеют значение NULL, поэтому индекс по field не будет использоваться вашим запросом (поскольку вы хотите найти все строки, где field равно NULL).

Или:

  • создайте индекс для (FIELD, 0), 0 будет действовать как ненулевой псевдостолбец, и все строки будут проиндексированы в таблице.
  • создайте индекс на основе функции для (CASE WHEN field IS NULL THEN 1 END), он будет индексировать только те строки, которые имеют значение NULL (поэтому индекс будет очень компактным). В этом случае вам придется переписать ваш запрос:

    UPDATE [TABLE] SET [FIELD]=0 WHERE (CASE WHEN field IS NULL THEN 1 END)=1

Edit:

Поскольку это разовый сценарий, вы можете использовать подсказку PARALLEL:

SQL> EXPLAIN PLAN FOR
  2  UPDATE /*+ PARALLEL(test_table 4)*/ test_table
  3     SET field=0
  4   WHERE field IS NULL;

Explained

SQL> select * from table( dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4026746538
--------------------------------------------------------------------------------
| Id  | Operation             | Name       | Rows  | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT      |            | 22793 |   289K|    12   (9)| 00:00:
|   1 |  UPDATE               | TEST_TABLE |       |       |            |
|   2 |   PX COORDINATOR      |            |       |       |            |
|   3 |    PX SEND QC (RANDOM)| :TQ10000   | 22793 |   289K|    12   (9)| 00:00:
|   4 |     PX BLOCK ITERATOR |            | 22793 |   289K|    12   (9)| 00:00:
|*  5 |      TABLE ACCESS FULL| TEST_TABLE | 22793 |   289K|    12   (9)| 00:00:
--------------------------------------------------------------------------------
5 голосов
/ 04 июня 2010

Обновляют ли другие пользователи те же строки в таблице одновременно?

Если это так, вы можете столкнуться с множеством проблем параллелизма (ожидание блокировок), и, возможно, стоит разбить его на более мелкие транзакции.

DECLARE
  v_cnt number := 1;
BEGIN
 WHILE v_cnt > 0 LOOP
   UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL AND ROWNUM < 50000;
   v_cnt := SQL%ROWCOUNT;
   COMMIT;
 END LOOP;
END;
/

Чем меньше ROWNUM, тем меньше проблем с параллелизмом и блокировками, но вы будете тратить больше времени на сканирование таблицы.

3 голосов
/ 03 июня 2010

Винсент уже отлично ответил на ваш вопрос, но мне любопытно, почему именно это действие. Почему вы обновляете все NULL на 0?

С уважением, Роб.

1 голос
/ 03 июня 2010

Некоторые предложения:

  1. Удалите все индексы, содержащие FIELD, перед выполнением оператора UPDATE, а затем добавьте их позже.

  2. Напишите для этого процедуру PL / SQL, которая фиксируется после каждых 1000 или 10000 строк.

Надеюсь, это поможет.

0 голосов
/ 03 июня 2010

Вы можете получить тот же результат без обновления, используя таблицу ALTER, чтобы установить для столбца значение «ПО УМОЛЧАНИЮ» значение 0.

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