После нескольких дней серфинга в Google я нашел самый простой и понятный пример восстановления свободного пространства в табличном пространстве после удаления. надеюсь, это поможет
Ссылка: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html
решение:
ALTER TABLE MOVE demo
Давайте создадим таблицу с 9999 строками, каждая размером около 1 КБ:
SQL> create table t (x char(1000) default 'x' primary key);
Table created.
SQL> insert /*+ append nologging */ into t(x) select rownum from all_objects where rownum < 10000;
9999 rows created.
SQL> commit;
Commit complete.
Для таблицы выделено 29 экстентов, в общей сложности 14,6M:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Давайте удалим ВСЕ строки:
SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.
Теперь - «сюрприз» - таблица все еще использует те же экстенты:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Почему ? Потому что даже если вы удалите все строки таблицы, High Water Mark не будет уменьшен - он никогда не будет уменьшен, чтобы обеспечить максимальный параллелизм (Oracle абсолютно серьезно относится к максимизации параллелизма, то есть производительности и масштабируемости; это главная причина его успеха в корпоративных приложениях).
Распределение неиспользуемого пространства (= пространство над HWM) мало помогает (так как над HWM не так много неиспользуемого пространства):
SQL> alter table t deallocate unused;
Table altered.
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 13959168
Теперь давайте переместим таблицу, что по сути означает клонировать таблицу (включая триггеры, ограничения и т. Д.), Перенести строки, удалить «старую» таблицу и переименовать новую - все сделано ядром, так что это супер-безопасно даже в случае отказа машины / сервера:
SQL> alter table t move;
Table altered.
Теперь у нас есть только начальный экстент:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536
Предупреждение: обычно случается, что многие / все индексы в таблице НЕПРАВИЛЬНЫ после перемещения (не в этом случае, но я использую 9.2.0.4, последний выпуск, который, вероятно, оптимизировал процесс в случае полностью пустых таблиц ):
SQL> col table_name form a30
SQL> col index_name form a30
SQL> set lines 123
SQL> select table_name, index_name, status from user_indexes where table_name='T';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ ------------------------
T SYS_C002573 VALID
Если STATUS не VALID, вы можете просто перестроить вручную индекс (ы):
SQL> alter index SYS_C002573 rebuild;
Index altered.
Или вы можете автоматизировать весь процесс:
set serveroutput on size 100000
begin
for n in (select index_name from user_indexes where status <> 'VALID') loop
dbms_output.put_line ('rebuilding ' || n.index_name);
execute immediate 'alter index ' || n.index_name || ' rebuild';
end loop;
end;
/
В качестве примера давайте вручную установим индекс на UNUSABLE:
SQL> alter index SYS_C002573 unusable;
Index altered.
SQL> set serveroutput on size 100000
SQL> begin
2 for n in (select index_name from user_indexes where status <> 'VALID') loop
3 dbms_output.put_line ('rebuilding ' || n.index_name);
4 execute immediate 'alter index ' || n.index_name || ' rebuild';
5 end loop;
6 end;
7 /
rebuilding SYS_C002573
PL/SQL procedure successfully completed.
HTH Альберто