oracle 12c收缩securefile lob空间唯一可靠方式是alter table modify lob配合shrink space,且必须lob为securefile类型、表空间启用assm,缺一不可。

Oracle 12c 中收缩 SECUREFILE LOB 段空间,唯一可靠方式是 ALTER TABLE MODIFY LOB 配合 SHRINK SPACE,且必须确认 LOB 是 SECUREFILE 类型、所在表空间启用了 ASSM(AUTO segment space management)——缺一不可。
确认 LOB 类型和表空间是否满足前提
执行收缩前不验证这两点,命令大概率静默失败或报错。常见误判是看到 ORA-43852 才意识到是 BASICFILE,或发现空间没变才回头查表空间类型。
- 查 LOB 类型:
SELECT table_name, column_name, securefile FROM dba_lobs WHERE table_name = 'YOUR_TABLE';—— 必须为YES - 查表空间管理方式:
SELECT tablespace_name, segment_space_management FROM dba_tablespaces WHERE tablespace_name = (SELECT tablespace_name FROM dba_lobs WHERE table_name = 'YOUR_TABLE');—— 必须为AUTO - 若
securefile = NO,SHRINK SPACE不支持,强行执行会报ORA-43852;此时只能走MOVE重建路径
执行 SHRINK SPACE 的语法与参数选择
SHRINK SPACE 对 SECUREFILE LOB 有效,但语法括号嵌套严格,漏掉任意一层括号都会报 ORA-00900 或 ORA-30871。
- 基础写法:
ALTER TABLE your_table MODIFY LOB (lob_col) (SHRINK SPACE);—— 注意外层MODIFY LOB和内层SHRINK SPACE的双括号 -
SHRINK SPACE COMPACT:只重组数据块,不下调 HWM,锁时间极短,适合业务高峰期分步操作;执行后dba_segments.blocks可能减少,但bytes不变 -
SHRINK SPACE(无 COMPACT):重组 + 下调 HWM,空间立即释放,但需短暂 X 锁,期间阻塞对该 LOB 列的读写 - 不支持
CASCADE,加了会报ORA-30871;LOB index 需单独处理或依赖自动维护
验证是否真收缩成功,别信 DBA_SEGMENTS.bytes
DBA_SEGMENTS.bytes 延迟更新、缓存干扰大,看它容易误判。真正有效的验证方式很窄:比对 LOB 段的 blocks 值是否下降。
- 先查 LOB 段名:
SELECT segment_name FROM dba_lobs WHERE table_name = 'YOUR_TABLE'; - 收缩前后分别执行:
SELECT segment_name, blocks FROM dba_segments WHERE segment_name = 'SYS_LOB0000XXXX$$'; - 若
blocks未变,可能原因有三:LOB 数据本身碎片率低、存在未提交事务、或有长期打开的 LOB locator(查v$lob和v$session_longops)
收缩后必须立刻收集统计信息
收缩完成不代表优化器“知道”空间已变。不手动刷新统计信息,执行计划仍按旧 blocks 和 num_rows 估算,极易引发全表扫描变慢、索引失效等性能倒退。
- 执行:
EXEC DBMS_STATS.GATHER_TABLE_STATS('YOUR_SCHEMA', 'YOUR_TABLE'); - 特别注意:如果表有分区,需指定
granularity => 'ALL',否则分区级统计可能遗漏 - LOB 列本身不参与列统计,但表级行数和块数变化直接影响 CBO 成本计算
真正难的不是敲那条 ALTER TABLE ... SHRINK SPACE,而是判断当前 LOB 数据是否真有可收缩空间、是否有长事务卡住 compact、以及收缩后要不要紧接着 resize 数据文件——这些没法靠一条 SQL 自动解决。











