Après avoir surfé sur Google pendant des jours, j'ai trouvé l'exemple le plus simple et le plus clair pour récupérer l'espace libre dans l'espace de table après la suppression. J'espère que ça aide
Lien: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html
Solution:
ALTER TABLE MOVE demo
Créons un tableau avec 9999 lignes, chacune d'environ 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.
Le tableau dispose de 29 extensions, pour un total de 14,6 millions:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Supprimons TOUTES les lignes:
SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.
Maintenant - "surprise" - la table utilise toujours les mêmes extensions:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Pourquoi ? Parce que même si vous supprimez toutes les lignes du tableau, le High Water Mark n'est pas diminué - il n'est jamais diminué, pour permettre une concurrence maximale (Oracle est très sérieux quant à la maximisation de la concurrence, c'est-à-dire les performances et l'évolutivité; c'est la principale raison de son succès dans les applications d'entreprise).
La désallocation de l'espace inutilisé (= espace au-dessus du HWM) n'aide pas beaucoup (car il n'y a pas beaucoup d'espace inutilisé au-dessus du 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
Maintenant, MOVONS la table, ce qui signifie essentiellement cloner la table (y compris les déclencheurs, les contraintes, etc.), transférer les lignes, supprimer la "vieille" table et renommer la nouvelle - le tout fait par le noyau, donc super-sûr même en cas de panne machine / serveur:
SQL> alter table t move;
Table altered.
Maintenant, nous avons maintenant seulement l'étendue initiale allouée:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536
Mise en garde: il arrive normalement que de nombreux / tous les index de la table soient inutilisables après le déplacement (pas dans ce cas, mais j'exécute 9.2.0.4, la dernière version, qui a probablement optimisé le processus en cas de tables totalement vides ):
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
Si STATUS n'était pas VALIDE, vous pouvez simplement reconstruire manuellement les index:
SQL> alter index SYS_C002573 rebuild;
Index altered.
Ou vous pouvez automatiser l'ensemble du processus:
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;
/
Par exemple, définissons manuellement l'index sur INUTILISABLE:
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