Direct Path Load 必然推高 HWM,因其跳过 buffer cache 和空间管理逻辑,只在 HWM 之上连续分配新区块,无法复用 HWM 下已删除或空闲空间。
Direct Path Load 为什么必然推高 HWM
因为 direct path load 的写入机制决定了它只能在高水位线(hwm)之上分配新数据块,无法重用 hwm 以下已删除或空闲的空间。这不是 bug,而是设计使然——它跳过 buffer cache 和空间管理逻辑,直接格式化并写入新区块。
传统 INSERT 和 Direct Path Load 对 HWM 的影响差异
传统 INSERT 会先检查 HWM 下的数据块是否有空闲空间(通过 freelist 或 ASSM 位图),有就复用;而 Direct Path Load 完全绕过这套检查,只看 HWM 位置,然后从 HWM+1 开始连续分配 extent。哪怕表里刚 DELETE 掉 90% 数据、HWM 下全是空块,它也视而不见。
-
INSERT INTO t SELECT ...(无 hint)→ 可能复用旧块,HWM 不变或缓慢上升 -
INSERT /*+ APPEND */ INTO t SELECT ...→ 必定在 HWM 上方追加,HWM 立即上移 -
TRUNCATE TABLE t→ 重置 HWM 到初始位置(段头)
HWM 抬高后带来的实际问题
最直接的后果是全表扫描性能下降:Oracle 在执行 SELECT * FROM t 时,仍需读取 HWM 以下所有块(包括大量空块或仅含少量行的块),导致物理读暴增。尤其在 11g 中,当表大小超过 _small_table_threshold,优化器更倾向走 direct path read,进一步放大 IO 压力。
- 即使表实际数据只有几 MB,HWM 被推到几十 GB,全扫照样慢
- 索引范围扫描不受影响,但基于该表的物化视图刷新、统计信息收集等后台任务也会变慢
-
SHRINK SPACE可降 HWM,但要求表启用ROW MOVEMENT,且期间会持表级锁
如何验证当前 HWM 位置
别只看 DBA_SEGMENTS.bytes,它反映的是已分配空间;真正关键的是 HWM 所在块号,可通过以下方式确认:
ANALYZE TABLE t ESTIMATE STATISTICS;<br>SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = 'T';
其中 blocks 是 HWM 以下总块数(含空块),empty_blocks 是明确标记为空但仍在 HWM 下的块数。二者之和越远大于实际数据所需块数,说明 HWM “虚高”越严重。
用 Direct Path Load 加速数据加载时,HWM 的不可逆抬升是默认代价——它不给你留“慢慢填满旧空间”的余地。如果后续需要频繁查询这张表,必须提前规划好 SHRINK 或 MOVE COMPRESS 的时机,否则性能衰减会悄无声息地发生。


















