SHRINK SPACE COMPACT不动HWM因其设计仅整理块内数据、不修改段头记录的HWM位置;它加RX锁允许并发DML,而SHRINK SPACE需X锁重写段头并下移HWM,且LOB段须单独收缩,否则空间无法真正释放。

SHRINK SPACE COMPACT 为什么不动 HWM?
因为 SHRINK SPACE COMPACT 的设计目标就是「只整理、不移动」:它把散落在高水位线(HWM)以下的行数据重新紧凑排列,填满空块,但不触碰段头(segment header)里记录的 HWM 位置。这就像整理书架——把歪斜的书扶正、塞紧,但不挪动书架最顶层那块隔板。
COMPACT 和 SHRINK SPACE 的锁行为差异
两者的底层动作和锁机制完全不同:
-
SHRINK SPACE COMPACT只加 RX(Row eXclusive)锁,允许并发 DML,适合业务高峰期分步执行 -
SHRINK SPACE在第二阶段必须获取 X(eXclusive)锁,会短暂阻塞所有 INSERT/UPDATE/DELETE,因为它要重写段头、更新 extent map 并真正下移 HWM - 执行
COMPACT后若不做SHRINK SPACE,查user_tables.blocks会发现数值不变——HWM 还钉在老地方
LOB 字段会让 COMPACT 彻底失效
这是最容易被忽略的坑:如果表含 LOB 列(如 CLOB、BLOB),SHRINK SPACE COMPACT 对 LOBSEGMENT 段完全无感。即使命令返回成功,dba_segments 中 LOB 段的 bytes 也纹丝不动。
原因在于 Oracle 的 shrink space 系列命令默认只作用于堆表段(segment_type = 'TABLE'),而 LOB 是独立段类型('LOBSEGMENT')。必须单独执行:
ALTER TABLE your_table MODIFY LOB (your_lob_col) (SHRINK SPACE);
漏掉这一步,哪怕堆表收缩了,90% 的空间照样浪费在 LOB 段里。
怎么验证 COMPACT 是否真起效?
别信命令返回的 “PL/SQL procedure successfully completed”,要看真实块级统计:
- 先收集统计:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'TABLE_NAME') - 再查关键字段:
SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = 'TABLE_NAME' - 如果
num_rows很小但blocks仍巨大,说明 HWM 没动,COMPACT只是把数据挤得更密了,没腾出新空闲区(extent)
真正释放空间给表空间,必须走完整流程:启用行移动 → COMPACT → SHRINK SPACE → (如有 LOB)单独 shrink LOB → 最后手动 RESIZE 数据文件。中间跳任何一环,操作系统就看不到磁盘空间回来。


















