收缩含lob的表段时,shrink space cascade不处理lob段,securefile lob需单独执行modify lob(col)(shrink space),basicfile lob不支持收缩;dba_segments.bytes有延迟,应查blocks确认;收缩后需alter database datafile resize释放操作系统空间。

收缩含LOB的表段,不能只用 SHRINK SPACE CASCADE
执行 ALTER TABLE t1 SHRINK SPACE CASCADE 后发现 SYS_LOB* 段大小没变,不是命令写错了,是 Oracle 明确设计为“跳过 LOB”。哪怕表里只有一个 SECUREFILE LOB 列,它也不会被连带处理。常见误判是查 DBA_SEGMENTS 看到 LOB 段 bytes 不变,就以为整个收缩失败——其实普通表段可能已成功收缩,只是 LOB 没动。
必须先确认 LOB 类型和表空间属性
SECUREFILE LOB 才支持在线收缩;BASICFILE LOB 完全不支持 SHRINK SPACE,19c 中强行执行会报 ORA-43852。收缩前务必验证两件事:
- 查
DBA_LOBS:确认securefile = 'YES',且对应tablespace_name在DBA_TABLESPACES中segment_space_management = 'AUTO' - 若查出是 BASICFILE,只能重建:用
MOVE PARTITION+REBUILD INDEX,且需额外空间 -
ENABLE ROW MOVEMENT对 LOB 收缩无影响,不用开
MODIFY LOB (col) (SHRINK SPACE) 的参数选择很关键
这是唯一能在线收缩 SECUREFILE LOB 的方式,语法括号不能省略,且不支持 CASCADE(加了报 ORA-30871):
-
SHRINK SPACE COMPACT:只重组数据块,不调高水位线(HWM),锁时间短,适合业务高峰期分步操作 -
SHRINK SPACE(无后缀):重组 + 调整 HWM,释放空间立竿见影,但需短暂独占锁,期间阻塞对该 LOB 列的读写 - 别信
DBA_SEGMENTS.bytes字段——它更新有延迟,且 LOB 段可能被缓存;最可靠的是查blocks:SELECT segment_name, blocks FROM dba_segments WHERE segment_name = 'SYS_LOB00000XXXX$$'
收缩后空间还在操作系统层?那得再走一步
SHRINK SPACE 只在数据库段级释放空间,操作系统级文件大小不会变。若想真正回收磁盘空间,得配合 ALTER DATABASE DATAFILE ... RESIZE。但注意:RESIZE 不能低于 HWM 位置,否则报 ORA-03297。可先用如下查询估算安全值:
SELECT a.file#, a.name,
ceil(HWM * a.block_size)/1024/1024 ResizeTo,
'alter database datafile '''||a.name||''' resize '|| ceil(HWM * a.block_size/1024/1024) || 'M;' ResizeCMD
FROM v$datafile a,
(SELECT file_id, max(block_id+blocks-1) HWM FROM dba_extents GROUP BY file_id) b
WHERE a.file# = b.file_id(+)
AND (a.bytes - HWM * a.block_size) > 0;
真正难的不是执行那条 SQL,而是判断该不该收缩、什么时候收缩、收缩后要不要立刻 resize 数据文件——这些没法靠一条命令解决。











