DEALLOCATE UNUSED 不释放HWM空间,因它仅回收段末尾完全未用的extents,不移动HWM;HWM下已格式化但空闲的块仍被锁定,需先执行SHRINK SPACE COMPACT下移HWM再配合使用。
DEALLOCATE UNUSED 为什么没释放高水位线(HWM)上的空间
deallocate unused 只回收段末尾未使用的区(extents),不移动高水位线(hwm)。它本质是“截断空闲尾巴”,不是“压缩已用块”。只要 hwm 以下有已格式化但未使用的数据块(比如删了大量行但没 shrink),这部分空间就仍被 hwm 锁定,deallocate unused 完全无视。
常见错误现象:SELECT blocks, empty_blocks FROM user_tables WHERE table_name = 'T' 显示 empty_blocks 很大,但执行 ALTER TABLE t DEALLOCATE UNUSED 后,表空间占用没变,dba_segments.bytes 不降。
- 仅当最后几个 extent 完全没被任何块使用过时才生效(比如刚 INSERT 一部分就回滚,或 TRUNCATE 后又部分 INSERT)
- 对 DELETE / UPDATE 后的表基本无效——那些块仍属于 HWM 下的“已分配但空闲”状态
- 需要先触发 HWM 下移(如
SHRINK SPACE COMPACT),再用DEALLOCATE UNUSED收尾才可能释放更多
什么时候该用 DEALLOCATE UNUSED,而不是 SHRINK SPACE
它适合轻量、低风险、不需锁表的释放场景,典型如:归档后清空分区末尾、LOB 段残留空闲 extent、索引重建后收缩尾部。和 SHRINK SPACE 相比,它不移动行、不重写数据、不需要启用行迁移(ROW MOVEMENT),也不触发 DML 锁(只持 DDL 锁极短时间)。
- 必须满足:表未启用
COMPRESS,且无基于函数的索引(否则 SHRINK 会报错,但 DEALLOCATE 仍可运行) - 不能跨块移动数据,所以无法释放 HWM 和最后一个已用 extent 之间的空隙
- Oracle 12c+ 中,对 IOT 的主键索引段也支持,但 secondary index 需单独处理
- 执行前建议先查:
SELECT segment_name, extents, blocks FROM dba_segments WHERE segment_name = 'T',确认末尾 extent 是否真为空
DEALLOCATE UNUSED 的实际执行要点
它不是“一键清理”,得看段结构是否配合。Oracle 检查的是 segment header 记录的 high water mark 和 extent map,如果最后几个 extent 在 bitmap 中标记为“全未使用”,才会真正从 extent map 中移除。
- 语法必须带
KEEP或不带:如ALTER TABLE t DEALLOCATE UNUSED KEEP 10K表示至少保留 10KB 空间不释放;不加KEEP则尽可能释放所有尾部空闲 extent - 对分区表,要指定分区:
ALTER TABLE t MODIFY PARTITION p1 DEALLOCATE UNUSED - 执行后立即生效,但不会更新
dba_extents视图直到下一次 extent 分配或 SMON 清理,可用SELECT COUNT(*) FROM dba_extents WHERE segment_name = 'T'对比前后 - 在 ASSM 表空间中,若段使用自动段空间管理,
DEALLOCATE UNUSED可能受 bitmaps 延迟刷新影响,稍等几秒再查更准
容易被忽略的兼容性与权限陷阱
它看着简单,但权限和版本细节一错就静默失败或报错。最常踩的坑是:以为有 ALTER 权限就够了,其实还依赖底层对象类型和表空间属性。
- 用户必须对表有
ALTER权限,且不是通过角色授予(必须直接授权) - 不能在只读表空间中执行,会报
ORA-00372: file xxx cannot be modified at this time - Oracle 11gR2 之前,对 SecureFile LOB 不支持;12c+ 支持,但必须确保
DB_SECUREFILE=IGNORE|PREFERRED,而非NEVER - 执行时若遇到
ORA-10631: SHRINK clause should not be specified for this object,说明对象类型不支持(如簇表、临时表),但DEALLOCATE UNUSED本身不报这个错——说明你误用了 SHRINK 语句
HWM 下的空间回收从来不是单条命令的事。DEALLOCATE UNUSED 只负责收尾,前面那步“怎么把 HWM 拉下来”才是关键。很多人卡在这儿,反复执行 DEALLOCATE 却看不到效果,其实是忘了先做 COMPACT 或 MOVE。










