TRUNCATE 默认等价于 DROP STORAGE,但仅重置HWM、不必然释放extents;真正释放需SHRINK SPACE、MOVE或expdp/impdp等物理重组手段。
truncate 默认不释放空间,是因为它只重置高水位线(hwm),不回收段(segment)所占的 extents —— 这是设计使然,不是 bug。
TRUNCATE 后空间没变:默认行为是 DROP STORAGE 还是 REUSE STORAGE?
Oracle 19c 中 TRUNCATE TABLE 的默认行为等价于 TRUNCATE TABLE ... DROP STORAGE,但它是否真能释放空间,取决于表所在段的管理方式和当前 HWM 位置:
- 若表使用自动段空间管理(ASSM)且 HWM 下方有大量空闲 extent,
DROP STORAGE通常会收缩到第一个可用 extent,但不一定归还给表空间 - 若表刚经历大规模插入(比如日志表涨到 100GB),即使
DROP STORAGE,Oracle 也可能保留大部分已分配的 extents,仅降低 HWM,不触发物理回收 -
REUSE STORAGE显式禁用空间回收,所有 extents 保留,仅清空数据、重置 HWM —— 这在 RAC 中可避免全局锁,但代价是空间完全不释放
为什么 ALTER TABLE ... DEALLOCATE UNUSED 不总生效?
ALTER TABLE ... DEALLOCATE UNUSED KEEP 0 看似能强制释放,但实际效果受限于底层段结构:
- 它只能释放“HWM 之上未使用的空间”,对 HWM 下方已分配但空闲的 extents 无效
- 如果表之前被
REUSE STORAGE截断过,或经历过大量 INSERT/DELETE 导致碎片化,DEALLOCATE UNUSED基本无作用 -
KEEP 0是关键:不加这个参数,语句只是检查并预留空间,不会真正释放
真正释放空间的可靠手段有哪些?
想让表占用的磁盘空间回落到合理水平,得绕过 TRUNCATE 的轻量机制,走物理重组路径:
- 用
ALTER TABLE ... SHRINK SPACE COMPACT:需先启用行移动(ENABLE ROW MOVEMENT),适合在线业务,但要求表无 LONG/LOB 以外的复杂类型 - 重建表:
ALTER TABLE t1 MOVE TABLESPACE users+ 重建索引,最彻底,但期间锁表,且 LOB 字段需额外指定LOB (col) STORE AS (TABLESPACE ...) - 导出+删除+导入(expdp/impdp):适用于大表且允许短时离线,能完全清理元数据和碎片
容易被忽略的关键点
很多人卡在“明明 TRUNCATE 了,DBA_SEGMENTS.BYTES 还是老样子”——这不是缓存延迟,而是 Oracle 把空间标记为“可重用”,但没义务立刻归还。监控时务必区分:
-
DBA_SEGMENTS.BYTES:已分配的段大小(虚高常见) -
DBA_FREE_SPACE.BYTES:表空间中真正空闲的块(反映真实可用) - 对临时表空间或 AWR 表这类特殊对象,TRUNCATE 甚至不适用,必须用
TRUNCATE PARTITION或FLUSH_AWR配合分区操作











