确认LOB段残留需查dba_segments中类型为'LOBSEGMENT'的对象,并关联dba_lobs定位归属表及列;若segment_name形如SYS_LOB0000092717C00005$$且dba_lobs无记录,则为孤儿LOB段。
表空间文件显示已用空间高但查不到对应数据,大概率不是“数据没删干净”,而是lob段残留或高水位未下降——这两类问题在oracle里不会随delete或truncate自动释放物理空间。
怎么确认是LOB段占着空间不放
先别急着清空表或重建表空间。直接查dba_segments里类型为LOBSEGMENT的对象,再关联dba_lobs看归属:
SELECT s.segment_name, s.bytes/1024/1024 "MB", l.table_name, l.column_name, l.securefile FROM dba_segments s, dba_lobs l WHERE s.segment_type = 'LOBSEGMENT' AND s.segment_name = l.segment_name AND s.owner = l.owner AND s.owner = 'YOUR_SCHEMA';
- 如果
securefile是NO,说明是BasicFile LOB,删数据后空间基本不回收,MOVE重构前一直占着 - 如果
segment_name像SYS_LOB0000092717C00005$$这种命名,且dba_lobs里查不到对应记录,说明LOB列定义过但后来被DROP COLUMN了,段却没清理——这是典型“孤儿LOB段” -
dba_lobs里查不到的LOB列,意味着它走的是STORAGE IN ROW(小LOB存行内),这类不单独成段,也不在本次排查范围内
为什么SHRINK SPACE对BasicFile LOB无效
ALTER TABLE ... SHRINK SPACE只支持SecureFile LOB,BasicFile用这个命令会报ORA-10631或直接忽略LOB部分。你看到“执行成功”,其实只是收缩了堆表,LOB段纹丝不动。
- BasicFile LOB要真正释放空间,只有两个路径:MOVE重构(推荐)或导出导入(停机成本高)
- SecureFile LOB才能用
SHRINK SPACE,20c起支持在线碎片整理:ALTER TABLE t MODIFY LOB c SHRINK SPACE - 哪怕表已是SecureFile,也要确认
dba_lobs.securefile = YES,别被db_securefile=FORCE误导——它只管新建表,不管已有段
高水位线卡住 vs 真实碎片:怎么区分
查dba_tables的blocks和num_rows能快速判断是否高水位问题:
SELECT table_name, blocks, num_rows, round((blocks * 8192) / 1024 / 1024) "ALLOCATED_MB" FROM dba_tables WHERE owner = 'YOUR_SCHEMA' AND table_name = 'YOUR_TABLE';
- 如果
num_rows = 0但blocks > 100,基本就是高水位没降,ALTER TABLE ... SHRINK SPACE COMPACT可能见效(需启用行移动) - 如果
num_rows很大但blocks异常高(比如比估算值高3倍以上),可能是表碎片严重,MOVE更稳妥 - 注意:
DBMS_SPACE.SPACE_USAGE过程不能用于BasicFile LOB,强行调用会报错;SecureFile LOB才支持第二种重载
MOVE重构LOB时最容易漏的三件事
MOVE不是执行一条语句就完事,漏掉任意一项都可能导致索引失效、空间不释放或操作失败:
- 必须显式带上
LOB (col_name) STORE AS SECUREFILE子句,否则LOB段原地不动,只搬了堆表 - 目标表空间必须是
SEGMENT SPACE MANAGEMENT AUTO(ASSM),否则ORA-43853直接报错 - MOVE后所有索引状态变成
UNUSABLE,必须逐个REBUILD ONLINE,分区表还要注意本地索引是否需要UPDATE GLOBAL INDEXES
SecureFile的压缩和去重效果高度依赖数据重复度,别一上来就写COMPRESS HIGH DEDUPLICATE——文本类LOB可能省30%,二进制附件可能几乎没变化,反而拖慢INSERT性能。


















