ALTER INDEX COALESCE不能减少叶块碎片,因为它仅合并相邻且空闲空间充足的叶块,不移动数据、不重排键序、不释放空块,对块内空洞和ITL争用无效;真正降低leaf_blocks须用REBUILD。 ALTER INDEX COALESCE 为什么不能减少叶块碎片 说到alter ind
说到alter index ... coalesce这个操作,很多人对它抱有不切实际的期望。实际上,它只做一件事:合并同一索引段里那些正好相邻、且各自都有不少空闲空间的叶块。它不会去移动数据行,不会重新排列键值的顺序,更不会把已经分配的空块释放回段里。本质上,这是一种“原地微调”,对于已经形成的叶块内部碎片——比如因为频繁delete或update产生的块内空洞——完全无能为力。
一个普遍的误解是,只要执行了COALESCE,叶块数量就会下降,blevel层级会降低,扫描性能自然就上去了。但现实情况是,这几乎不会发生。原因在于它的工作机制非常局限:
长期稳定更新的攒劲资源: >>>点此立即查看<<<
blevel保持不变)。num_rows不变,leaf_blocks通常也纹丝不动)。INITRANS设置过低或高并发更新导致的ITL(事务槽)争用型碎片,它同样束手无策。那么,想要实质性地降低leaf_blocks、压缩物理存储、重新排序键值,并清理ITL和空洞,出路只有一条:ALTER INDEX ... REBUILD。这个操作会分配一个新的段,然后逐行重写所有的索引条目,并按照当前的PCTFREE设置和排序规则,将数据紧密地填充到新的叶块中。
这里有个细节需要注意:默认情况下(Oracle 12c及以上),REBUILD是在线操作,但它会持有DL(Direct Load)锁,这会阻塞相关的DDL操作。如果加上ONLINE关键字,则允许并发DML,但代价是会产生更多的重做日志,占用更高的临时段空间,执行时间也会更长。
针对不同场景,可以这样选择重建策略:
REBUILD PCTFREE 0(需谨慎,这意味着后续几乎没有更新预留空间)。PCTFREE设为10到20之间,比原值略低即可。TABLESPACE new_ts子句,一举两得完成物理重组。NOPARALLEL NOLOGGING(前提是可以接受该索引无法通过归档日志恢复)。判断碎片是否严重,不能只看DBA_INDEXES.leaf_blocks或者INDEX_STATS里的DEL_LF_ROWS(已删除的叶行数)。关键要看运行时的实际表现:
SELECT /*+ INDEX(t idx) */ COUNT(*) FROM t WHERE ...的查询时,逻辑读(logical reads)远高于估算的叶块数乘以2。V$SEGMENT_STATISTICS视图中,该索引的gc cr block lost或db block gets指标异常偏高。ANALYZE INDEX ... VALIDATE STRUCTURE后查询INDEX_STATS,发现索引高度HEIGHT > 4,并且LF_ROWS / LF_BLKS(每块平均行数)过低。话说回来,如果仅仅是DEL_LF_ROWS / LF_ROWS > 30%(删除行数占比超过30%),但系统的查询响应依然稳定,那大概率不需要急着去干预它。
当然有,但它的适用场景非常狭窄。它仅适用于一种特殊情况:刚刚批量DELETE了大量连续的键值(例如,按时间顺序删除了半年前的分区数据),并且这些删除恰好集中在索引末尾的几个相邻叶块上。此时,COALESCE有可能把这些半空的块合并成一个,并释放回空闲列表(freelists)。不过,这种理想情况在常见的OLTP系统中极少出现。
那么,它更现实的用途是什么呢?可以把它看作一种“轻量级预热”或“顺手清理”的手段。在业务低峰期执行一次COALESCE,成本极低(几乎不锁表,也不占用临时空间),万一运气好,凑巧清理掉一两个块,就算是额外收获。但绝不能把它当作治理碎片的主力手段。
归根结底,控制碎片的关键在于预防。在建索引时就合理设定PCTFREE,避免在高并发更新的字段上建立非必要的索引,并定期使用REBUILD来替代盲目的COALESCE操作。后者虽然名字里带着“合并”,干的却是一件最保守的活儿。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述