Nachdem ich tagelang bei Google gesurft habe, habe ich das einfachste und klarste Beispiel gefunden, um den freien Speicherplatz im Tablespace nach dem Löschen zurückzugewinnen. ich hoffe das hilft
Link: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html
Lösung:
ALTER TABLE MOVE demo
Erstellen wir eine Tabelle mit 9999 Zeilen mit einer Größe von jeweils ca. 1 KB:
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.
Der Tabelle sind 29 Bereiche zugeordnet, insgesamt 14,6 Millionen:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Löschen wir ALLE Zeilen:
SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.
Nun - "Überraschung" - die Tabelle verwendet immer noch die gleichen Ausmaße:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064
Warum ? Denn selbst wenn Sie alle Zeilen der Tabelle löschen, wird die High Water Mark nicht verringert - sie wird nie verringert, um maximale Parallelität zu ermöglichen (Oracle ist absolut ernsthaft mit der Maximierung der Parallelität, dh Leistung und Skalierbarkeit; dies ist der Hauptgrund für den Erfolg in Unternehmensanwendungen).
Die Freigabe des nicht genutzten Speicherplatzes (= Speicherplatz über dem HWM) hilft nicht viel (da über dem HWM nicht viel nicht genutzter Speicherplatz vorhanden ist):
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
Verschieben wir nun die Tabelle, was im Wesentlichen bedeutet, die Tabelle zu klonen (einschließlich Trigger, Einschränkungen usw.), die Zeilen zu übertragen, die "alte" Tabelle zu löschen und die neue umzubenennen - alles vom Kernel erstellt, also super sicher auch bei Maschinen- / Serverausfall:
SQL> alter table t move;
Table altered.
Jetzt haben wir nur noch den anfänglichen Umfang zugewiesen:
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536
Vorsichtsmaßnahme: Normalerweise sind viele / alle Indizes in der Tabelle nach dem Verschieben NICHT VERWENDBAR (nicht in diesem Fall, aber ich verwende 9.2.0.4, die neueste Version, die den Prozess bei vollständig leeren Tabellen wahrscheinlich optimiert hat ):
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
Wenn STATUS nicht GÜLTIG wäre, könnten Sie die Indizes einfach manuell neu erstellen:
SQL> alter index SYS_C002573 rebuild;
Index altered.
Oder Sie können den gesamten Prozess automatisieren:
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;
/
Lassen Sie uns als Beispiel den Index manuell auf UNUSABLE setzen:
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