必须先收集分区统计信息,再通过blocks与num_rows比值判断物理碎片;未更新统计会导致90%误判,(blocks×8192)/num_rows>avg_row_len+100或num_rows/blocks过低均表明hwm下空洞严重。
查分区hwm:先确认统计信息是否新鲜
oracle不会自动维护分区级的blocks和empty_blocks,所以直接查user_tab_partitions可能返回空值或过期数据。不收集统计信息就评估碎片,等于靠猜——90%的“高碎片”误判都源于这一步跳过。
- 必须先对目标分区执行:
DBMS_STATS.GATHER_TABLE_STATS,且显式指定granularity => 'PARTITION' - 避免用
ESTIMATE,尤其对大分区,务必加method_opt => 'FOR ALL COLUMNS SIZE AUTO'保证列统计准确 - 检查是否生效:查
LAST_ANALYZED列,时间应≤5分钟前;再看BLOCKS是否非空
定位物理碎片:看BLOCKS和NUM_ROWS比值
分区HWM的本质是“已分配但未必填满的数据块总数”,它藏在BLOCKS字段里。真正反映碎片的是这个值和实际数据量的偏离程度——不是看删除了多少行,而是看每行平均占多少块。
- 计算公式:
(BLOCKS * 8192) / NUM_ROWS(单位字节),若结果 >AVG_ROW_LEN + 100,说明块内空洞严重 - 更直观的阈值判断:
NUM_ROWS / BLOCKS (即平均每块不到10行),基本可判定存在显著物理碎片 - 注意
EMPTY_BLOCKS对分区无效,该字段在分区表中恒为0,别被它误导
验证碎片是否真实影响性能:全扫分区时到底读多少块
高水位线真正拖慢查询,是因为全表扫描(或分区扫描)必须遍历HWM以下所有块,哪怕它们全是空的。但Oracle有优化:如果分区启用了COMPRESS或INMEMORY,实际I/O可能远低于BLOCKS值。
- 开启10046跟踪,执行
SELECT COUNT(*) FROM your_table PARTITION (p2025_q3),看physical reads是否接近BLOCKS - 对比
db file sequential read等待次数:若远高于NUM_ROWS,说明大量单块读空块,碎片确实在起作用 - 禁用并行(
/*+ NO_PARALLEL */)再测,排除并行协调块干扰判断
别急着MOVE:先区分DELETE和TRUNCATE分区的后果
对分区执行TRUNCATE PARTITION会重置该分区HWM为0,而DELETE只是标记行失效,HWM纹丝不动——这是最常被混淆的点。但MOVE PARTITION也不是万能解药,它会失效本地索引、中断正在运行的查询。
-
TRUNCATE PARTITION:快、干净、HWM归零,但不可回滚,且要求无全局索引依赖 -
ALTER TABLE ... MOVE PARTITION:可选UPDATE INDEXES维持索引,但需排他锁,DML阻塞时间≈数据量×网络延迟 - 小技巧:先用
EXCHANGE PARTITION把旧分区换出到临时表,清空后再换回,兼顾在线性和HWM重置
真正麻烦的永远不是怎么降HWM,而是降完之后本地索引状态是否一致、物化视图日志有没有断、应用SQL执行计划有没有突变——这些细节不验,降完HWM反而引发新问题。










