Depois de navegar no google por dias, encontrei o exemplo mais simples e claro para recuperar o espaço livre no espaço de tabela após a exclusão. Eu espero que isso ajude
Link: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html
solução:
ALTER TABLE MOVE demo
Vamos criar uma tabela com 9999 linhas, cada uma com tamanho em torno de 1k:
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.
A tabela possui 29 extensões alocadas, totalizando 14,6 milhões:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Vamos excluir TODAS as linhas:
SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.
Agora- "surpresa" - a tabela ainda usa as mesmas extensões:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Por quê ? Porque, mesmo que você exclua todas as linhas da tabela, a marca d'água máxima não diminui - nunca diminui, para permitir a máxima concorrência (a Oracle leva muito a sério a maximização da concorrência, ou seja, desempenho e escalabilidade; é a principal razão por trás do sucesso em aplicativos corporativos).
Desalocar o espaço não utilizado (= espaço acima do HWM) não ajuda muito (já que não há muito espaço não utilizado acima do 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
Agora, vamos MOVER a tabela, que basicamente significa clonar a tabela (incluindo gatilhos, restrições e assim por diante), transferir as linhas, largar a tabela "antiga" e renomear a nova - tudo feito pelo kernel, tão super seguro mesmo em caso de falha da máquina / servidor:
SQL> alter table t move;
Table altered.
Agora, temos agora apenas a extensão inicial alocada:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536
Advertência: normalmente acontece que muitos / todos os índices da tabela ficam INUSÁVEIS após a movimentação (não neste caso, mas estou executando o 9.2.0.4, a versão mais recente, que provavelmente otimizou o processo no caso de tabelas totalmente vazias ):
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
Se o STATUS não fosse VÁLIDO, você poderia simplesmente reconstruir manualmente o (s) índice (s):
SQL> alter index SYS_C002573 rebuild;
Index altered.
Ou você pode automatizar todo o processo:
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;
/
Como exemplo, vamos definir manualmente o índice para 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 Alberto