DELETE 不释放物理空间且HWM不变是正常行为;SHRINK SPACE需先启用行移动,仅回收段内空间;缩文件须RESIZE且确保末尾有连续空闲。

DELETE 不动高水位线(HWM),也不释放数据文件物理空间——这不是异常,是 Oracle 段管理的正常行为。
DELETE 后 BLOCKS 字段不变,全表扫描还是那么慢
-
BLOCKS来自USER_TABLES,它反映的是当前 HWM 下已分配的块总数,不是“实际有数据的块数” -
DELETE只把行标为“已删除”,块仍归属该段,HWM 一动不动 - 全表扫描(FTS)必须读到旧 HWM 位置,哪怕
NUM_ROWS = 0,IO 量没省 - 常见误判:看到
DBA_SEGMENTS.BYTES没变,就以为“空间卡住了”,其实它本来就不该变
验证是否 HWM 虚高:
先刷新统计:EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME')
再查关键字段:SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = 'TABLE_NAME'
- 若
num_rows极小(比如100),但blocks仍是几万 → HWM 明显虚高 -
empty_blocks越大,说明 HWM 下“逻辑空块”越多,空间浪费越实
SHRINK SPACE 执行报 ORA-10636:没开行移动
-
ALTER TABLE ... SHRINK SPACE要求先启用行移动,否则直接报错ORA-10636: row movement is not enabled - 必须分两步:
ALTER TABLE your_table ENABLE ROW MOVEMENTALTER TABLE your_table SHRINK SPACE- 加
COMPACT(如SHRINK SPACE COMPACT)只整理块内碎片,不降 HWM,期间允许 DML - 不带
COMPACT才真正移动 HWM,但会短暂加 X 锁,所有 DML 阻塞 - 加
CASCADE可连带收缩索引,避免后续手动ALTER INDEX ... SHRINK SPACE
- 加
- 收完记得关掉:
ALTER TABLE your_table DISABLE ROW MOVEMENT
否则可能干扰依赖ROWID的逻辑(如某些物化视图、审计触发器)
SHRINK SPACE 完了,磁盘文件大小还是没变
-
SHRINK SPACE只回收段内空间,让空闲块归还给表空间;它完全不碰数据文件(.dbf)的物理尺寸 - 操作系统看不到空间释放,是因为文件头尾没动,
ls -lh或 Windows 属性里大小纹丝不动 - 必须手动
RESIZE数据文件,且要满足前提:先确认末尾真有连续空闲空间:
SELECT file_name, bytes/1024/1024 AS curr_mb, (bytes - NVL((SELECT SUM(bytes) FROM dba_free_space WHERE file_id = d.file_id), 0))/1024/1024 AS used_mb FROM dba_data_files d WHERE tablespace_name = 'YOUR_TS'- 只有
curr_mb - used_mb > 100(MB)以上,才值得收缩 - 执行:
ALTER DATABASE DATAFILE <file_id> RESIZE <new_size>M - 注意:不能小于当前已用空间,否则报
ORA-03297
- 只有
HWM 是段级概念,RESIZE 是文件级操作,中间隔着表空间空闲链表和本地管理机制。很多人卡在“收缩了表却忘了缩文件”,或者缩文件时没校验末尾空闲是否连续——这两步漏掉任何一环,磁盘空间就永远“看着空,实则占着”。


















