truncate能释放segment级空间(如dba_extents记录、重置hwm),但不缩小datafile物理大小,也不释放minextents预留空间;需显式加drop storage或后续执行deallocate unused keep 0才能真正归还表空间。

TRUNCATE 能释放表占用的空间,但默认不缩回数据文件物理大小,也不清空 minextents 占用的初始空间。 它释放的是 segment 级别的空间(即表和索引的 extent),不是 datafile 级别的磁盘空间。很多 DBA 执行完 TRUNCATE TABLE 后发现 dba_free_space 没变、df -h 磁盘使用率也没降,就是卡在这个认知偏差上。
TRUNCATE 后空间没“消失”?先确认它到底释放了什么
执行 TRUNCATE TABLE t1 后:
- ✅
dba_extents中该表对应的所有 extent 记录被清除 —— segment 空间已归还给表空间 - ✅ 高水位线(HWM)重置到段头位置,新插入数据会从头开始分配块
- ❌ 数据文件(
dba_data_files)大小不变,OS 层磁盘空间未回收 - ❌ 如果表定义了
MINEXTENTS(比如 8),即使清空后,segment 仍保留至少 8 个 extent 的预留空间 - ❌ LOB 字段若未显式指定
INCLUDING DATA,LOB segment 可能残留,需查dba_lobs
想真正“缩小”空间?必须加 DROP STORAGE 或 DEALLOCATE UNUSED
默认行为是 REUSE STORAGE(隐式),即保留原存储结构。要让 Oracle 把 segment 空间真正交还给表空间(从而可能提升 dba_free_space 值),得显式声明:
-
TRUNCATE TABLE t1 DROP STORAGE:释放所有非MINEXTENTS占用的空间,segment 缩到最小(但不会低于MINEXTENTS) -
ALTER TABLE t1 DEALLOCATE UNUSED KEEP 0:在 truncate 后补这一句,强制释放 HWM 以下所有未用空间(比DROP STORAGE更激进) - 注意:
KEEP 0是关键,不加则默认保留部分空间;执行前确保表无活跃事务
外键、物化视图日志等依赖导致 TRUNCATE 失败怎么办
常见报错:ORA-02266(外键引用)、ORA-02449(唯一/主键被引用)、ORA-12083(有物化视图日志):
- 有外键子表时,用
TRUNCATE TABLE parent CASCADE(Oracle 12c+ 支持),否则需先禁用或删除外键约束 - 有物化视图日志,加
PRESERVE MATERIALIZED VIEW LOG可保留日志,加DROP MATERIALIZED VIEW LOG则一并清理(12c+) - 表被物化视图直接引用(非日志),
TRUNCATE会失败,必须先DROP物化视图或改用DELETE + SHRINK - 执行后统计信息失效,首次查询可能硬解析,建议后续跑
DBMS_STATS.GATHER_TABLE_STATS
TRUNCATE vs DELETE + SHRINK:什么情况该选哪个
核心区别不在“快慢”,而在“是否带条件”和“是否可逆”:
- 整表清空且无需回滚 → 无脑用
TRUNCATE,速度快、redo 少、不触发 trigger - 只删部分数据(如保留最近 30 天)→ 必须用
DELETE WHERE,之后跟ALTER TABLE t1 ENABLE ROW MOVEMENT和ALTER TABLE t1 SHRINK SPACE - 想连 datafile 一起缩容 →
TRUNCATE或SHRINK都做不到,得用ALTER DATABASE DATAFILE ... RESIZE(前提:free space 连续且在文件末尾) - LOB 字段多、碎片严重 →
SHRINK SPACE COMPACT比TRUNCATE更安全(不重置 HWM,可分步执行)
真正容易被忽略的点:TRUNCATE 不解决 datafile 物理大小问题,而 DBA 监控看到的往往是 OS 层磁盘告警 —— 此时盯着 dba_data_files.bytes 和 df -h 才是关键。











