2012-03-20 1 views
0

Я работаю над oracle 9i. У меня есть таблица с 135 000 000 записей, разделенных, где каждый раздел имеет ок. 10 000 000 строк. все проиндексировано и все.Оптимизировать Удалить запрос с большим количеством данных на oracle

Мне нужно удалить около 70 000 000 строк из этого как новое деловое требование.

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

Table1 <col1, col2........> -- main table (135,000,000 rows) 

Table2 <col1, col2........> -- backup table (70,000,000 rows) 

Пробовал нижеследующий запрос на удаление.

Delete from table1 t1 where exists (select 1 from table2 t2 where t2.col1 = t1.col1) 

, но это занимает бесконечные часы.

затем попытался

declare 
cursor c1 is 
select col1 from table2; 
c2 c1%rowtype; 
cnt number; 
begin 
cnt :=0; 
open c1; 
loop 
    fetch c1 into c2; 
    exit when c1%notfound; 

    delete from table1 t1 where t1.col1 = c2.col1; 
    if cnt >= 100000 then 
     commit; 
    end if; 
    cnt:=cnt+1; 
end loop; 
close c1; 
end; 

даже до сих пор его работает уже в течение более 12 часов. и все еще не завершены.

Обратите внимание, что в таблице 1 есть несколько индексов и индекс на col1 на таблице2. анализируются все таблицы и индексы.

Просьба сообщить, есть ли способ оптимизации для этого сценария.

Спасибо, ребята.

+0

Если ваш код действительно выглядит так, вы будете фиксировать для каждой строки после строки 100000, что, вероятно, не то, что вы хотите, и будет медленным, конечно. Задайте свой cnt: = 0 после фиксации –

+0

Ya counter требует перезагрузки Я думаю, что это была опечатка. Но я предпочел отказаться от индексов и воссоздать, поскольку главный ответ –

ответ

4

Отбросьте все индексы (подпорка создавать операторы) Используй оператор выбора, который используется для создания таблицы резервного копирования, создать из него команда DELETE Recreate всего индекс

4

Я помню, перед этим вопросом раньше. В этом случае, мы прибегли к делать это, так как он работал быстрее, чем любая другая операция удаления:

1) Создайте другую таблицу с идентичной структурой

2) Вставьте в новую таблицу запись, которые вы хотите сохранить (используйте прямую вставку пути ускорить этот)

3) падение старой таблице

4) переименовать новую таблицу

0

я собираюсь ответить на этот вопрос при условии, что он дешевле фильтровать против резервного копирования стол, но это ould, вероятно, будет дешевле просто использовать отрицание критериев, которые вы использовали для заполнения таблицы резервного копирования.

1) создать новый стол с той же структурой. Нет индексов, ограничений или триггеров.

2)

 
    select 'insert /*+ append nologging */ into new_table partition (' || n.partition_name || ') select * from old_table partition (' || o.partition_name || ') minus select * from bak_table partition (' || b.partition_name || ');' 
    from all_tab_partitions o, all_tab_partitions n, all_tab_partitions b 
    where o.partition_no = all(n.partition_no, b.partition_no) 
     and o.table_name = 'OLD_TABLE' and o.table_owner = 'OWNER' 
     and n.table_name = 'NEW_TABLE' and n.table_owner = 'OWNER' 
     and b.table_name = 'BAK_TABLE' and b.table_owner = 'OWNER'; 
    -- note, I haven't run this it may need minor corrections in addition to the obvious substitutions 

3) проверить и запустить результат предыдущего запроса

4) строить индексы, ограничения и триггеры при необходимости

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

Вы могли бы идти быстрее параллельно insert + parallel select, но, вероятно, это необязательно. Просто не делайте параллельный выбор без вставки и «alter session enable parallel dml»

+0

'nologging' - не настоящий намек, вам нужно только« append ». –

1

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

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

CREATE TABLE rows_to_save 
    AS SELECT * 
     FROM table1 
     WHERE <<criteria to select the 65 million rows you want to keep>> 

TRUNCATE TABLE table1; 

INSERT /*+ append */ 
    INTO table1 
SELECT * 
    FROM rows_to_save; 

Запрета, что, вместо того чтобы создавать таблицы резервного копирования , было бы более эффективным, чтобы просто выдать DELETE заявления

DELETE FROM table1 
WHERE <<criteria to select the 70 million rows you want to keep>> 

Вы также можете воспользоваться падением или отключения индексов и ограничений перед запуском DELETE.