lob段不随表truncate自动收缩,因其是独立段,物理上与主表分离,truncate仅重置表hwm而不处理lob段;需显式执行alter table modify lob(...)(shrink space)或drop column等操作才能释放其空间。

LOB段不随表TRUNCATE自动收缩,因为它是独立段
Oracle里LOB列(如CLOB、BLOB)的数据默认不和表数据存在一起,而是单独分配一个LOB段。这个段在逻辑上属于表,物理上却是完全独立的存储单元——有自己的段头、extent链、高水位线(HWM),甚至可能在不同表空间里。所以当你执行TRUNCATE TABLE时,Oracle只重置表本身的HWM、释放堆表段空间,但对关联的LOB段不做任何操作。
TRUNCATE后LOB段仍占大量空间的典型现象
你执行完TRUNCATE TABLE t,查DBA_SEGMENTS发现表段大小归零了,但t_lobs(或系统生成的SYS_LOB0000xxxx$$)段还占几百MB,SELECT SUM(bytes) FROM DBA_EXTENTS WHERE SEGMENT_NAME LIKE 'SYS_LOB%' AND OWNER = 'YOUR_SCHEMA'还能扫出大量已分配未清理的extents。
- 这不是bug,是设计行为:Oracle把“清空表”和“清理LOB存储”视为两个可分离的操作
-
TRUNCATE不触发LOB的SHRINK SPACE,也不调用DBMS_LOB.FREETEMPORARY这类清理逻辑 - 即使表里所有LOB字段值都是NULL,只要曾经插入过非空LOB,对应LOB段就一直存在且不自动回收
真正释放LOB段空间的实操路径
必须显式干预,不能依赖表级DDL:
- 先确认LOB段名:
SELECT SEGMENT_NAME, TABLESPACE_NAME FROM DBA_LOBS WHERE TABLE_NAME = 'T' AND OWNER = 'YOUR_SCHEMA' - 如果LOB段无数据(全为NULL或已清空),可用
ALTER TABLE t MODIFY LOB(col) (SHRINK SPACE)—— 但要求表启用了行移动:ALTER TABLE t ENABLE ROW MOVEMENT - 若要彻底删除LOB段(连同结构),得先
DROP COLUMN col,再ALTER TABLE t DROP UNUSED COLUMNS,否则段残留 - 极端情况(如测试库快速腾空间):直接
DROP TABLE t CASCADE CONSTRAINTS,LOB段随表一并物理删除
为什么ALTER TABLE ... SHRINK SPACE常失败?关键限制点
SHRINK SPACE对LOB不是无条件生效的,容易卡在几个硬性门槛上:
- 表必须启用
ROW MOVEMENT,否则报ORA-10636: row movement is not enabled - LOB列不能是
DISABLE STORAGE IN ROW且CHUNK大于数据库块大小,否则收缩被跳过 - 如果LOB段所在表空间是
ASSM(自动段空间管理),且存在大量未格式化的block,SHRINK可能只回收部分空间,需配合DBMS_SPACE.SPACE_USAGE验证实际可用量 - 在线业务中执行
SHRINK会持TM锁,阻塞DML,别在高峰期跑
最易被忽略的是:哪怕你成功跑了SHRINK,它也只影响当前分区(如果是分区表),非全局生效——得逐个分区处理,或者改用MOVE PARTITION加UPDATE INDEXES组合拳。











