谷歌浏览了几天后,我找到了最简单明了的示例,在删除后回收表空间中的可用空间。我希望这有帮助
链接:http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html
解:
ALTER TABLE MOVE demo
让我们创建一个表,其中包含9999行,每行大小约为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.
该表已分配给它29个扩展,总计1460万:
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
为什么呢 因为即使删除表的所有行,高水位线也不会降低-不会降低,以实现最大的并发性(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
如果状态不是有效的,则可以简单地手动重建索引:
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 Alberto