TRUNCATE TABLE能自动回收空间,因其是DDL操作,重置HWM、释放segment所有extent,使空间可被表空间复用,但不缩小数据文件物理大小。

直接用 TRUNCATE TABLE 清空整表时,空间怎么就“自动回收”了?
TRUNCATE TABLE 是 DDL 操作,它不走回滚段、不记录单行 undo、不触发触发器,执行后会立即重置高水位线(HWM),并释放该表 segment 占用的所有 extent。你在 DBA_EXTENTS 里查不到该表的 extent 记录,说明空间已从 segment 层面归还给表空间。
但注意:这**不等于物理数据文件变小**。数据文件(.dbf)大小不变,只是内部可分配空间变多了。如果想真正缩小文件,得后续执行 ALTER DATABASE DATAFILE ... RESIZE,且前提是文件末尾有连续空闲区。
- 必须是整表清空——
TRUNCATE不支持WHERE - 若表被物化视图日志、外键引用或启用 IOT,可能报
ORA-02266或ORA-02449 - 执行后统计信息失效,首次查询可能硬解析;依赖
ROWID的应用逻辑需验证
用 DELETE 删除部分数据后,为什么 SHRINK SPACE 总失败?
DELETE 只标记行为空闲,HWM 不动,空间还在那里“占着坑”。这时想在线回收,必须靠 SHRINK SPACE,但它对前置条件很敏感:
- 表必须启用了行移动:
ALTER TABLE t ENABLE ROW MOVEMENT,否则报ORA-10636 - 只能用于 ASSM(自动段空间管理)表空间,字典管理表空间会报
ORA-10635 - 不能有函数索引、域索引或位图连接索引——这些会让
ENABLE ROW MOVEMENT失败 - 执行
SHRINK SPACE时会阻塞 DML;SHRINK SPACE COMPACT则允许并发 DML,但不降 HWM
常见误操作:删完数据就直接 SHRINK,忘了先 ENABLE ROW MOVEMENT,或者没检查表空间类型。
大表只删一部分,又不想停业务,还能怎么收空间?
当你要保留部分数据(比如按时间分区保留最近 6 个月),TRUNCATE 和 SHRINK 都不适用。更稳妥的做法是“重建式清理”:
- 用
CREATE TABLE t_new AS SELECT * FROM t WHERE ...把要留的数据导出 -
DROP TABLE t(原表 segment 空间彻底释放) -
RENAME t_new TO t,再重建索引、约束、授权
这种方式能彻底重置 HWM、消除碎片、避免行迁移副作用,但需要足够临时空间,且期间原表不可写。适合维护窗口明确的大表。
注意:RENAME 后所有依赖该表的对象(视图、包、同义词)不会自动更新,需手动验证或运行 @?/rdbms/admin/utlrp.sql 编译无效对象。
回收空间后,磁盘没变小,是不是没成功?
绝大多数情况下,“空间回收”指 segment 级别(逻辑空间),不是操作系统级文件大小。即使 TRUNCATE 或 SHRINK 成功,数据文件仍保持原大小。
真要缩小物理文件,得单独操作:
- 查文件当前最小可 resize 大小:
SELECT bytes, blocks FROM dba_data_files WHERE file_name = '...';再结合dba_extents算末尾空闲块 - 执行:
ALTER DATABASE DATAFILE '/path/to/file.dbf' RESIZE 1024M; - 如果 resize 失败,说明文件末尾有未释放的 extent——此时需先
SHRINK或MOVE表,再试
最易忽略的一点:删完文件后,Linux 下若仍有 Oracle 进程持有句柄,磁盘空间不会释放,得用 lsof -n | grep deleted 找 PID 并 kill,或重启数据库实例。


















