HWM过高会导致全表扫描性能严重下降,因其强制Oracle扫描高水位线下所有块(含大量空块),即使表仅剩100行而HWM位于100万块处;可通过dba_tables.blocks / num_rows > 50且avg_row_len < 200等指标间接判断,而DELETE不降HWM,须用SHRINK SPACE、MOVE或TRUNCATE等DDL操作才能释放。
怎么确认HWM是否真成了瓶颈
全表扫描变慢不等于hwm高,但hwm过高会让扫描范围虚增——哪怕表里只剩100行数据,只要hwm卡在100万块位置,table access full仍要遍历到那块为止。关键看两点:dba_segments.blocks(已分配块数)和dba_tables.num_rows(真实行数)的比值。如果blocks / num_rows > 50,且avg_row_len不大(比如<200字节),大概率是hwm膨胀了。
DBA_TABLES里哪些字段暴露HWM问题
dba_tables本身不存HWM值,但以下字段组合能间接反映:
-
num_rows:当前统计行数(需确保近期收集过) -
blocks:已分配的数据块总数(含空块) -
empty_blocks:HWM之上、从未用过的块数(注意:9i后默认不统计,设STATISTICS_LEVEL = BASIC才可能为0) -
avg_space:HWM之下、已分配块中的平均空闲字节数;若该值持续>1000,说明大量块半空,HWM没回落
执行时别只查单次快照,对比dba_tab_statistics.last_analyzed前后两次的blocks变化——如果num_rows几乎不变但blocks翻倍,就是典型HWM滞涨。
收缩HWM的实操限制与替代方案
Oracle不提供直接“降低HWM”的命令,只能靠重建释放空间:
-
ALTER TABLE ... SHRINK SPACE COMPACT:要求表启用行移动(ENABLE ROW MOVEMENT),且不能有基于函数的索引或域索引 -
MOVE操作:会失效所有索引,必须后续ALTER INDEX ... REBUILD,且期间表不可DML(除非用ONLINE重定义) - 分区表可逐个
TRUNCATE PARTITION再EXCHANGE,但非分区表没这捷径
注意:SHRINK不会降低段高水位线以下的已用块数,只整理碎片;真正释放空间给OS,得靠MOVE + ALTER TABLE ... DEALLOCATE UNUSED。
为什么刚DELETE完HWM也不降
这是最常被忽略的点:DELETE只是把行标记为“可重用”,不回收块,HWM纹丝不动。即使COMMIT了,SELECT COUNT(*)变小,blocks字段也完全没变化。验证方式很简单:
执行ANALYZE TABLE t COMPUTE STATISTICS后查dba_tables.blocks,再做一次DELETE+COMMIT,立刻再ANALYZE——数值必然一致。只有TRUNCATE(DDL)或上述SHRINK/MOVE才能动HWM。


















