DELETE不降低HWM是Oracle设计行为,仅标记行为空闲;要降HWM须重建段(如MOVE、CTAS或DBMS_REDEFINITION)或用TRUNCATE(DDL,不可回滚)。

DELETE 不降低高水位线(HWM)是默认行为
Oracle 中 DELETE 语句只是标记行为空闲,不回收数据块,也不重置段的高水位线(HWM)。这意味着即使删掉 90% 的数据,全表扫描仍会读到 HWM 以下所有块(包括空块),性能可能无改善。这不是 bug,而是设计使然——DELETE 需支持回滚、触发器、细粒度权限等事务特性,无法像 DDL 那样直接重置结构。
实操建议:
- 若目标是释放空间并降低 HWM,
DELETE单独使用无效,必须配合后续操作 - 确认当前 HWM:可查
DBA_SEGMENTS的BYTES和BLOCKS,再对比DBA_TABLES.NUM_ROWS × AVG_ROW_LEN估算实际占用,差值大说明 HWM 悬空严重 - 注意
DELETE后未COMMIT时,HWM 不变;已COMMIT后,HWM 依然不变——这点常被误认为“提交后空间就释放了”
想用 DELETE 但又降 HWM?只能重建段
真正让 DELETE “附带降 HWM 效果”的唯一办法,是删除后重建段结构。这不是 DELETE 本身的能力,而是借它做数据筛选+重组织的组合动作。
常用路径(按安全性和适用性排序):
-
ALTER TABLE ... MOVE:最直接。执行前需确保无 LONG 列、无函数索引依赖;MOVE 后索引失效,必须ALTER INDEX ... REBUILD -
CREATE TABLE AS SELECT (CTAS)+DROP+RENAME:更可控,适合大表或需加过滤条件(如只保留近 3 个月数据)。注意外键、权限、统计信息需手动迁移 -
DBMS_REDEFINITION:在线重定义,业务不停机,但配置复杂,要求主键或伪主键,且对物化视图日志有依赖
三者共性:都绕过了 DELETE 的逻辑删除限制,用物理重建把 HWM 拉回到真实数据边界。
TRUNCATE 确实重置 HWM,但它是 DDL 且不可回滚
TRUNCATE TABLE 是 DDL 操作,立刻释放区(extents),将 HWM 重置为初始值(通常是 segment header 下第一个可用块),且不走 rollback segment。这是它和 DELETE 最本质的区别,不是“更快一点”,而是“完全不同的机制层级”。
关键差异点:
-
TRUNCATE不触发DELETE触发器,不校验外键约束(除非CASCADE),也不记录 undo —— 所以执行后FLASHBACK TABLE也无法恢复 - 若表启用了行移动(
ENABLE ROW MOVEMENT)或有 IOT,TRUNCATE仍有效;但如果有正在运行的查询引用该表(如未关闭的游标),可能报ORA-00054: resource busy -
TRUNCATE默认释放空间到表空间,但加REUSE STORAGE可保留分配的空间(即不清空 extent,只重置 HWM),适合频繁清空又快速回填的场景
别混淆“空间显示释放”和“HWM 下降”
很多人看到 DBA_FREE_SPACE 里空闲空间变多了,就以为 HWM 降了。其实不然:DELETE 后高水位线以上空间确实归还给表空间(free space 增加),但 HWM 本身纹丝不动。下次 INSERT 仍从 HWM 处开始写,而全表扫描、FTS、某些索引范围扫描仍受旧 HWM 影响。
验证是否真降 HWM 的最简方式:
- 执行前后分别运行:
ANALYZE TABLE t_name COMPUTE STATISTICS,再查DBA_TABLES.BLOCKS—— 这个值反映的是 HWM 下的块数,而非分配总块数 - 或用
DBMS_SPACE.SPACE_USAGE查unformatted_blocks,若该值接近total_blocks - used_blocks,说明 HWM 已贴近真实数据
HWM 是 Oracle 成本计算(CBO)和 I/O 路径的关键输入,忽略它去调优 SQL 或索引,常常白忙一场。











