При выполнении массовых удалений в Oracle
, убедитесь, что у вас не заканчивается UNDO SEGMENTS
.
При выполнении DML
, Oracle
сначала записывает все изменения в журнал REDO
(старые данные вместе с новыми данными).
Когда журнал REDO
заполнен или истекло время ожидания, Oracle
выполняет log synchronization
: он записывает данные new
в файлы данных (в вашем случае помечает блоки данных как свободные) и записывает старые данные в табличное пространство UNDO
(чтобы оно оставалось видимым для одновременных транзакций до тех пор, пока вы commit
не внесете изменения).
Когда вы фиксируете свои изменения, пространство в UNDO
сегментах, занятых вашей транзакцией, освобождается.
Это означает, что если вы удалите 5M
строк данных, вам потребуется место для all
этих строк в ваших UNDO
сегментах, чтобы данные могли быть перемещены туда первыми (all at once
) и удаляется только после коммита.
Это также означает, что параллельные запросы (если таковые имеются) должны будут считывать из REDO
журналов или UNDO
сегментов при выполнении сканирования таблиц. Это не самый быстрый способ доступа к данным.
Это также означает, что если оптимизатор выберет HASH JOIN
для вашего запроса на удаление (что он, скорее всего, сделает), а временная таблица не будет вписываться в HASH_AREA_SIZE
(что, скорее всего, будет иметь место), тогда для запроса потребуется several
сканирование большой таблицы, а некоторые части таблицы уже будут перемещены в REDO
или UNDO
.
.
Учитывая все сказанное выше, вам, вероятно, лучше удалить данные в 200,000
кусках и зафиксировать изменения между ними.
Таким образом, вы, во-первых, избавитесь от проблем, описанных выше, и, во-вторых, оптимизируете свой HASH_JOIN
, поскольку у вас будет такое же количество операций чтения, но сами чтения будут более эффективными.
В вашем случае, однако, я бы попытался заставить оптимизатор использовать NESTED LOOPS
, так как я ожидаю, что в вашем случае это будет быстрее.
Чтобы сделать это, убедитесь, что ваша временная таблица имеет первичный ключ на ID
, и перепишите ваш запрос следующим образом:
DELETE
FROM (
SELECT /*+ USE_NL(tt, tn) */
tn.id
FROM temp_table tt, table_name tn
WHERE tn.id = tt.id
)
Вам потребуется первичный ключ на temp_table
, чтобы этот запрос работал.
Сравните это со следующим:
DELETE
FROM (
SELECT /*+ USE_HASH(tn tt) */
tn.id
FROM temp_table tt, table_name tn
WHERE tn.id = tt.id
)
, посмотрите, что быстрее, и придерживайтесь этого.