LOB段HWM不能直接shrink因Oracle设计限制:shrink不支持含独立存储LOB的表,尤其启用RETENTION或存在未提交事务时;DBMS_REDEFINITION可重置HWM,但须显式指定STORE AS SECUREFILE并执行MODIFY LOB(...SHRINK SPACE)。
LOB段高水位线为什么不能直接 shrink
因为 alter table ... shrink space 对含 lob 列的表默认不生效,尤其当 lob 存储在单独段(securefile 或 basicfile)且启用了 retention 或存在未提交事务时,oracle 会跳过 lob 段收缩。这不是 bug,是设计限制:lob 数据块管理逻辑和堆表不同,shrink 无法安全定位“真正可回收”的旧块。
DBMS_REDEFINITION 能否真正重置 LOB 段 HWM
可以,但必须满足两个硬性前提:
• 目标表的 LOB 列需显式指定 STORE AS SECUREFILE(哪怕源是 BASICFILE),否则新段仍沿用旧存储参数,HWM 不会重置;
• 执行 DBMS_REDEFINITION.FINISH_REDEFINITION 后,必须立刻对新表的 LOB 列执行 ALTER TABLE ... MODIFY LOB (...) (SHRINK SPACE),否则只是“搬数据”,没触发空间回收。
常见错误现象:ORA-10631: SHRINK clause should not be specified for this object —— 说明当前 LOB 段未启用 SECUREFILE 或未启用 ENABLE ROW MOVEMENT。
- 使用场景:历史归档后大表
LOB占用率长期低于 5%,但dba_segments.bytes无变化 - 参数差异:
DBMS_REDEFINITION.START_REDEFINITION的options_flag必须传dbms_redefinition.cons_use_pk或dbms_redefinition.cons_use_rowid,不能省略 - 性能影响:在线重定义期间,源表 DML 可继续,但
LOB写入会产生额外日志量,建议避开业务高峰
实操中必须检查的 4 个关键点
漏掉任意一项都会导致 HWM 未下降或报错:
- 确认源表
LOB是否启用了RETENTION:SELECT retention FROM dba_lobs WHERE table_name = 'YOUR_TABLE';若非0,重定义前需先ALTER TABLE ... MODIFY LOB (...) (RETENTION 0) - 目标表建表语句中,
LOB子句必须包含STORE AS SECUREFILE和显式TABLESPACE,不能依赖默认表空间 -
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS调用时,copy_indexes参数建议设为0(不复制索引),等重定义完成后再手工重建,避免索引指向旧LOB段 - 执行完
FINISH_REDEFINITION后,立刻查dba_lobs确认segment_name已变更,再运行ALTER TABLE ... MODIFY LOB (...) (SHRINK SPACE)
收缩后空间没释放?先看这三行 SQL
别急着重跑重定义,先验证是否真没释放:
SELECT segment_name, bytes/1024/1024 mb FROM dba_segments WHERE segment_name IN ( SELECT segment_name FROM dba_lobs WHERE table_name = 'YOUR_TABLE' );
对比重定义前后结果;再查实际占用:
SELECT SUM(bytes)/1024/1024 mb_used FROM dba_extents WHERE segment_name IN ( SELECT segment_name FROM dba_lobs WHERE table_name = 'YOUR_TABLE' );
如果 mb_used 明显小于 mb,说明 HWM 已降,只是 Oracle 还没把 extent 归还给表空间——此时需手动 ALTER TABLESPACE ... COALESCE(针对 LMT)或等待 SMON 清理(可能延迟数小时)。
最常被忽略的是:SHRINK SPACE 对 SECUREFILE LOB 默认只回收未使用的块,不合并碎片;如需彻底压缩,得加 CASCADE,但会锁表几秒:ALTER TABLE t MODIFY LOB (c) (SHRINK SPACE CASCADE)。










