TRUNCATE 后高水位线(HWM)不降;默认仅释放空间但保留已分配区,HWM 保持原位,需显式加 DROP STORAGE 才重置;LOB 字段需单独处理;EXP/IMP 导入可重置 HWM,因重建表结构。
TRUNCATE 后高水位线真的降了吗?
不降。truncate 是 ddl 操作,默认会释放空间,但仅当指定 drop storage 时才真正重置高水位线(hwm)。oracle 默认行为是保留段中已分配的区(extents),hwm 停留在原位置,后续 insert 仍从原 hwm 开始写入。
常见错误现象:SELECT COUNT(*) FROM table 返回 0,但 DBA_SEGMENTS 中 BLOCKS 和 BYTES 完全没变;执行全表扫描或并行查询仍很慢——因为 Oracle 还得一路扫到旧 HWM。
- 显式加
TRUNCATE TABLE t DROP STORAGE才能回收全部空间、重置 HWM - 若表有 LOB 字段,需额外对
LOBSEGMENT单独TRUNCATE或SHRINK SPACE - 注意权限:需要
ALTER ANY TABLE或表级ALTER权限,且不能在有未提交事务的会话中执行
EXP/IMP 导入导出能降低 HWM 吗?
能,但只在特定条件下生效。传统 EXP(exp.exe)导出 + IMP(imp.exe)导入默认重建表结构,相当于「新建一张空表再插入数据」,HWM 自然从头开始。但这不是 magic,本质是绕过了原表的物理存储残留。
使用场景:适合中小规模表(
-
IMP必须用IGNORE=Y跳过对象已存在错误,否则报ORA-00955: name is already used by an existing object - 导入后表的
INITIAL和NEXT参数沿用原 EXP 时的值,未必最优;建议导入后手动ALTER TABLE ... STORAGE (INITIAL 64K NEXT 64K) -
EXP的COMPRESS=Y(默认)会导致所有数据插入第一个区,可能引发热点块争用;生产环境建议设为COMPRESS=N
比 TRUNCATE 和 EXP/IMP 更稳的替代方案:SHRINK SPACE
ALTER TABLE ... SHRINK SPACE 是在线、可控、可逆的 HWM 下压方式,要求表启用行移动(ENABLE ROW MOVEMENT),且不能有基于函数的索引或域索引。
性能影响明显:它会触发实际数据块整理和 HWM 下推,过程中表可读可写(但 DML 可能短暂阻塞),而 TRUNCATE 是 DDL 锁全表,EXP/IMP 需要停应用。
- 执行前必须先开行移动:
ALTER TABLE t ENABLE ROW MOVEMENT - 带
CASCADE可同时收缩分区、LOB 段和索引:ALTER TABLE t SHRINK SPACE CASCADE - 如果报
ORA-10636: row movement is not enabled,别硬改参数,先确认是否漏了ENABLE ROW MOVEMENT - 收缩后记得收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS,否则执行计划可能劣化
为什么有时候 HWM 降了查询还是慢?
因为 HWM 只控制“全表扫描读到哪”,不代表数据分布合理。比如大量 DELETE 后做 SHRINK,块内可能仍稀疏(PCTFREE 过高、链式行未清理),或索引叶块未重组,导致逻辑读暴涨。
容易被忽略的点:HWM 下降 ≠ 索引 B 树高度下降 ≠ 缓冲区命中率提升。你看到 DBA_EXTENTS 的 BLOCK_ID 变小了,但真实 I/O 效率还卡在别的环节。
- 查块利用率:
ANALYZE TABLE t COMPUTE STATISTICS后看AVG_SPACE和CHAIN_CNT - 索引需单独
ALTER INDEX ... REBUILD或COALESCE,SHRINK SPACE不动索引结构 - 如果用了 ASSM(自动段空间管理),
SHRINK效果受FREELISTS/FREELIST GROUPS影响极小,但手工段管理(MSSM)下必须留意
事情说清了就结束










