INSERT /+ APPEND / 必然推高HWM,因其绕过空闲块检查,直接分配新extent并格式化未用块,使HWM跳至新extent末尾;普通INSERT在ASSM下当无可用空闲块时亦会触发extent分配致HWM上升。

因为 INSERT(尤其带 APPEND)会直接分配新 extent 并推进 HWM,不经过空闲块检查。这不是“延迟更新”或“统计滞后”,而是 Oracle 段空间管理的底层机制决定的——HWM 是已分配块的边界标记,只要分配了新块,HWM 就必须上移。
APPEND 模式下 INSERT 为什么必然推高 HWM
使用 INSERT /*+ APPEND */ 时,Oracle 绕过常规的 freelists / bitmap 空闲块查找流程,直接向段末尾请求新 extent。即使 HWM 下方存在大量 empty_blocks,也不会复用:
- APPEND 是 direct-path 写入,只写入新分配的、未格式化的块(格式化发生在第一次写入时)
- 每次分配 extent(默认 8 个 block 起),HWM 就跳到该 extent 的最后一个 block 之后
- 即使只插入 1 行,只要触发了新 extent 分配,HWM 就涨
普通 INSERT 在 ASSM 表空间中也可能推高 HWM
在自动段空间管理(ASSM)下,普通 INSERT 虽会优先尝试复用 HWM 下的空闲块,但仍有明确条件会突破 HWM:
- 当当前 extent 中所有块都被标记为“full”(位图显示无可用空间),且没有其他非满 extent 可用时,会分配新 extent → HWM 上移
- 并发插入高峰时,多个会话同时申请空间,可能因位图同步延迟导致重复分配 → HWM 非预期上升
- 表设置了
PCTFREE=0或行非常大,导致单个 block 很快被填满,加速 extent 耗尽
如何验证某次 INSERT 是否推高了 HWM
不要依赖 user_tables.blocks(那是已使用块数,含空块),而要看实际段级分配:
- 执行 INSERT 前后分别查:
SELECT blocks FROM dba_segments WHERE segment_name = 'YOUR_TABLE' - 对比结果:若
blocks增加,说明分配了新 extent,HWM 已上升 - 再查:
SELECT COUNT(*) FROM dba_extents WHERE segment_name = 'YOUR_TABLE',看 extent 数是否增加
注意:ANALYZE TABLE ... COMPUTE STATISTICS 后查 user_tables.empty_blocks 只反映 HWM 下“已分配但从未用过”的块,不能反推 HWM 是否变动。
容易被忽略的关键点
HWM 不是“数据量水位”,而是“已分配空间水位”。哪怕你 INSERT 后立刻 DELETE 所有行,dba_segments.blocks 不变,HWM 也纹丝不动——这就是为什么仅靠删数据永远清不掉膨胀的物理空间。真正可控的只有分配行为本身:避免无节制 APPEND、合理设置 INITIAL/NEXT extent 大小、对批量导入场景预估空间并提前 ALTER TABLE ... ALLOCATE EXTENT。


















