Обновить все строки


12

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

update mytable set mycolumn=null;

или:

update mytable set mycolumn=42;

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


Насколько я понимаю, добавление нового ненулевого столбца со значением по умолчанию - это изменение метаданных только в Oracle. Я сомневаюсь, что они оптимизировали случай "обновить все строки до одинакового значения". Это обычная операция для вас?
Мартин Смит

1
Просто попробуйте оба метода и время их. Что мешает вам сделать это? Вот факт, что вы должны закончить с тем же результатом, а не с другим результатом! В противном случае сравнение недопустимо.
tvCa

@tvCa Я пробовал оба пути. Если я просто делаю обновление, оно запускается около двух часов, а затем я убиваю его. Если я опущу столбец, это займет всего несколько секунд. Добавление столбца без значения по умолчанию (которое обнуляет столбец) занимает всего несколько секунд. Добавление столбца со значением по умолчанию занимает около 30 минут. Поэтому, если я хочу, например, установить для всех значений в столбце значение «Некоторое значение», я в данный момент отбрасываю и добавляю столбец. Я просто хочу знать, есть ли более быстрый способ сделать это.
Kainaw

2
Вы используете 11gR2? @MartinSmith - это правильно. См. Здесь описание того, как добавление нового столбца с DEFAULT как NOT NULL является гораздо более быстрым изменением, чем добавление его как NULL, что приведет к обновлению всех строк в таблице (так же, как и при выполнении оператора UPDATE). Проблема, которую я вижу, - это удаление значения DEFAULT впоследствии, потому что повышение производительности происходит из-за сохранения DEFAULT в словаре. Вам также придется иметь дело с ограничением NOT NULL в этой точке.
анзибль

Ответы:


2

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

  1. Запустить сингл update table set column_name = blah;
  2. Создайте цикл plSql, чтобы выбрать все первичные ключи в таблице и просмотреть их, updating the column=blahа также зафиксировать каждые X обновлений (возможно, 10000). Вы можете распараллелить этот код, скопировав его и сделав его копированием, сделав отдельный раздел Первичных ключей.

У нас была очень похожая проблема с таблицей, которая очень активно использовалась в системе OLTP, и мы смогли распараллелить ее 5 раз и запустить без влияния блокировки пользователя на таблицу строк более 100 ММ, фиксирующую каждые 10000. Вы не сказали, как большой размер вашего стола или какое приложение вы используете, но такое решение может вам подойти.


0

Для быстрого UPDATE, убедитесь, что у вас нет триггеров, которые стреляют.

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Не забудьте включить только те, которые вы хотите, когда вы закончите.

ALTER TRIGGER mytrigger ENABLE;

Вы также можете столкнуться с накладными расходами на обслуживание индекса. Попробуйте перестроить ваши индексы отдельно. Чтобы сделать это, здесь должен быть полезен ответ Паппеса: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Я повторяю ответ Папес здесь для справки. (Обратите внимание, что эта команда SPOOL делает предположения о вашей платформе и среде.)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

Делать импорт ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

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


-2

Если у вас нет ограничения по пространству, вы можете создать новую таблицу, такую ​​же, как ваша таблица, с добавленным в нее новым столбцом и удалить старую таблицу:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
Будет ли это более эффективным? Почему? А что если есть ФК, которые ссылаются на существующую таблицу?
ypercubeᵀᴹ

да, вы можете попробовать это на другом примере таблицы и увидеть результат самостоятельно. Если есть ФК, я точно не знаю, но вы можете отключить и включить их, если это эффективно.
E_Salamon

-3

Попробуйте несколько обновлений / коммитов. Вставка / обновление / удаление слишком большого количества строк без фиксации приводит к большой нагрузке ввода-вывода. Он может быть довольно оптимизирован, зная размеры блоков, записи размеров и прочего.

Для удаления целых данных в таблице, truncate table xлучше, чем delete from x. Также очистка делает другую рабочую нагрузку процесса.

Редактировать: Вы можете использовать inmemoryопцию, загружая таблицу в память в столбчатом формате, а затем выполнить обновление. это действительно зависит от отношений и структуры вашей БД. Смотрите эту статью .


3
Они хотят обновить один столбец таблицы. Я не понимаю, как truncateили deleteбудет какой-либо помощи.
ypercubeᵀᴹ

@ypercube Я только что объяснил, как множественные манипуляции с данными без фиксации приводят к нежелательной загрузке ввода-вывода; быть обновлением или другими OLTP.
Хитрость

3
Не могли бы вы объяснить, как частые коммиты уменьшают количество операций ввода-вывода? Не увеличат ли они ввод-вывод из-за контрольных точек?
Мустаччо

3
Использование вами нетрадиционной терминологии («журнал tx», «очищает ваш сеанс») немного сбивает с толку. Используете ли вы несколько коротких транзакций или одну массивную транзакцию, общий объем созданных записей повторов будет одинаковым. Операции ввода-вывода выполняются только тогда, когда буфер журнала повторных операций записывается на диск (пока остаются одни контрольные точки буферного кэша), что происходит при фиксации или когда буфер повторных операций почти заполнен. Впоследствии, если вы делаете коммит часто, вы вызываете дополнительные операции ввода-вывода, поэтому мне интересно, как это может уменьшить количество операций ввода-вывода.
Мустаччо

4
Возможно, вы захотите прочитать то, что Том Кайт говорит о «частых коммитах »: asktom.oracle.com/pls/apex/… " неправильно, неправильно, неправильно. Так неправильно .... Так очень неправильно "
a_horse_with_no_name
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.