Может ли блокировка таблицы ускорить выполнение инструкции обновления в Oracle 10g enterprise?


У нас есть довольно широкая таблица BaseData с некоторыми 33 миллионами строк в ней. Затем у нас есть запрос обновления, который соединяет его с несколькими другими таблицами, содержащими все виды параметров, применяются некоторые функции, есть группа по исходному идентификатору, а затем результаты записываются обратно в таблицу BaseData в нескольких столбцах.

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

Я подозреваю, что во время обновления Oracle создает версии каждой строки, чтобы любой читатель Oh мог прочитать эту незатронутую строку. Однако это требует значительных ресурсов. Есть ли какой-либо способ заставить обновление взять блокировку записи в таблице, чтобы оно не создавало версии каждой строки?

У вас есть еще какие-нибудь советы для больших обновлений? Мы уже разбили его на партии. Каждый пакет находится в отдельном разделе таблицы, а затем выполняется несколько обновлений параллельный. Но все равно все это слишком медленно.

3 2

3 ответа:

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

Итак, первый вопрос заключается в том, что медленнее-это вся работа по объединению и применению функций, или это обратная запись? Как работает SELECT my_updated_resultset FROM BASEDATA JOIN... по сравнению с вашим оператором update? Вы это проверили есть разногласия между читателями BaseData и процессом обновления? Кроме того, это слишком медленно для бизнеса, или просто медленнее, чем вы думаете?

Еще один вариант, который следует рассмотреть, - это использование partition exchange для выполнения обновлений. Концепция высокого уровня будет выглядеть следующим образом:

  1. CREATE TABLE BASEDATA_XCHG as SELECT * FROM BASEDATA WHERE 1 = 0;
  2. INSERT /*+ append */ INTO BASEDATA_XCHG SELECT my_updated_resultset FROM BASEDATA PARTITION (ONLY_ONE_PARTITION) JOIN...
  3. создайте все необходимые индексы и ограничения в таблице BASEDATA_XCHG.
  4. ALTER TABLE BASEDATA EXCHANGE PARTITION (ONLY_ONE_PARTITION) WITH BASEDATA_XCHG

Если вы обновляете большинство строк в a раздел таблицы BASEDATA, не обновляйте их-создайте новую таблицу и замените ее. У Тима Гормана есть превосходная статья под названием"масштабирование до бесконечности", которая охватывает эту концепцию более глубоко; возможно, вы захотите ее проверить.

В дополнение к ответу Адама:

Запустите план объяснения в инструкции update и проверьте план выполнения.

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

Oracle использует сегменты отмены для обеспечения согласованности чтения (наряду с SCNs, подробнее здесь)

Я предполагаю, что эти большие пакетные процессы выполняются в промежуточной области, а не в экземпляре" prod", который используется множеством различных процессов. Если вы обновляете 25% или более (приблизительные цифры) некоторой большой таблицы, возможно, лучше сделать CTAS (create table as select...) чем попытки обновления. Ваши CTAS будут содержать логику обновления для новой таблицы. После этого добавьте индексы / гранты / etc на новой таблице и переименовать новое в старое. Вы также можете добавить параллельную подсказку и nologging на CTAS, чтобы потенциально ускорить события еще больше.