孤立段指数据字典标记删除但物理段仍残留的段,需通过DBA_SEGMENTS与DBA_OBJECTS比对、块内容验证及V$BH状态确认;19c+可用DBMS_SPACE.CLEAN_UP_SEGMENT_SPACE清理。
孤立段怎么判断?别信dba_segments的bytes字段
孤立段(orphaned segment)不是指“没人用的表”,而是指数据字典里已标记删除、但物理段头块和extent仍残留的段。典型现象是:dba_segments里还查得到某表或索引,dba_objects却查不到对应对象;或者select count(*) from table_name报ora-00942,但dba_segments显示它占了几十gb。
根本原因通常是:DROP TABLE未加PURGE、闪回误操作后强制清理、或RAC节点间SCN不一致导致SMON没完成段回收。此时BYTES值不可信——它反映的是段头块记录的分配量,不是真实可读数据。
确认步骤:
- 查
DBA_SEGMENTS中SEGMENT_TYPE为TABLE或INDEX,但OWNER在DBA_OBJECTS中无对应记录 - 运行
SELECT segment_name, header_file, header_block FROM dba_segments WHERE segment_name = 'XXX';,再用ALTER SYSTEM DUMP DATAFILE X BLOCK Y;验证块内容是否为空或含乱码 - 检查
V$BH中该段的buffer header是否长期STATE = 'free'且CR_SCN_BAS = 0
DBMS_SPACE.UNUSED_SPACE能查出什么?别当它能定位孤立段
DBMS_SPACE.UNUSED_SPACE只返回某个段内**已分配但未使用的空间**,比如高水位线(HWM)以上的空闲块,或ASSM段中未格式化的block。它对孤立段完全无效——因为孤立段的segment header可能已损坏,调用这个过程会直接报ORA-03203或ORA-06512。
真正该用的是DBMS_SPACE.OBJECT_SPACE_USAGE,但它要求对象必须“逻辑存在”。所以处理孤立段的第一步永远不是查空间,而是先确认它是不是真孤立:
- 执行
SELECT * FROM DBA_RECYCLEBIN WHERE ORIGINAL_NAME = 'XXX';,有结果说明还在回收站,直接PURGE TABLE "BIN$xxx" - 查
DBA_LOBS和DBA_TAB_PARTITIONS,确认没被LOB或分区子表隐式引用 - 在12c+环境,用
SELECT * FROM V$SEGMENT_STATISTICS WHERE OBJECT_NAME = 'XXX';看是否有活跃I/O统计
DBMS_SPACE.CLEAN_UP_SEGMENT_SPACE:Oracle 19c+才有的救命命令
19c引入的DBMS_SPACE.CLEAN_UP_SEGMENT_SPACE是唯一能安全触发孤立段物理回收的系统过程。它不依赖SMON,也不走常规DDL路径,而是直接扫描段头块并重置extent map。但必须满足三个硬条件:
- 数据库兼容性参数
COMPATIBLE >= '19.0.0'(查V$PARAMETER确认) - 目标段所在表空间必须是本地管理(
EXTENT_MANAGEMENT = LOCAL)且使用ASSM(SEGMENT_SPACE_MANAGEMENT = AUTO) - 执行用户需有
ANALYZE ANY DICTIONARY权限,且不能在PDB中跨容器调用(得切到CDB$ROOT)
示例调用:
BEGIN
DBMS_SPACE.CLEAN_UP_SEGMENT_SPACE(
segment_owner => 'SCOTT',
segment_name => 'BIG_TABLE',
segment_type => 'TABLE'
);
END;执行后立刻从DBA_SEGMENTS消失,DBA_FREE_SPACE中对应表空间的空闲空间上涨。注意:它不缩数据文件,也不降低HWM,只是把extents标记为“可重用”。
为什么不用ALTER TABLE ... SHRINK SPACE?它根本不认孤立段
ALTER TABLE ... SHRINK SPACE要求表必须处于OPEN状态、启用行移动(ENABLE ROW MOVEMENT),且段头块结构完整。对孤立段执行会直接报ORA-10636或ORA-01410(invalid ROWID),因为它试图读取一个已失效的segment header。
更危险的是:有人试过先TRUNCATE TABLE再SHRINK,结果触发SMON异常——因为truncate对孤立段是静默失败,后续shrink会基于错误的HWM计算,导致部分block被错误标记为“已分配”,最终引发ORA-00600 [ktsj_delete_extent]。
真正该做的只有两件事:
- 19c+:用
DBMS_SPACE.CLEAN_UP_SEGMENT_SPACE(见上条) - 12c–18c:手动唤醒SMON,再等它扫完——
ORADEBUG SETMYPID; ORADEBUG WAKEUP SMON;,然后监控V$SESSION_LONGOPS中OPNAME = 'SMON: space management'的进度
孤立段最难缠的点不在技术动作,而在于它往往藏在SYSAUX或SYSTEM表空间里,而这两个表空间的段清理受严格保护。一旦发现SEGMENT_NAME以WRH$_或WRI$_开头的孤立段,优先怀疑AWR快照清理失败,而不是直接动DBMS_SPACE包。


















