全局索引在oracle 11g rac中易引发gc争用,因其叶块不按分区键分布,导致多实例争抢修改同一索引块;本地索引通过写入隔离、维护原子化、统计可下推和隐式分区裁剪缓解该问题,但需校验唯一性约束、跨分区扫描需求及分区键合理性。
全局索引在 oracle 11g rac 上天然容易引发 gc 争用,不是“性能差”,而是设计目标不匹配。
为什么全局索引在 RAC 中会拖慢写入
全局索引的叶块不按分区键分布,所有实例插入新行时都可能修改同一组索引块(尤其主键/时间戳升序场景)。这直接导致:
-
gc current block busy等待飙升:多个节点争抢修改同一个索引块,LMS 进程频繁传输 current 块 - 反向键索引失效:即使加了
REVERSE,范围扫描无法走,而 OLTP 中大量等值查询又依赖该优化 - 分区维护代价高:
ALTER TABLE ... DROP PARTITION会触发全局索引重建(UNUSABLE后需REBUILD),期间锁表且生成巨量 redo - 统计信息滞后:
DBMS_STATS.GATHER_TABLE_STATS默认不收集全局索引的分区级统计,CBO 容易选错执行计划
本地分区索引如何缓解 GC 压力
本地索引与表分区严格对齐,每个分区索引段只被对应表分区的 DML 访问。关键效果:
- 写入隔离:节点 A 插入
PARTITION P2024的数据,只修改本地索引分区IX_LOCAL_P2024,不触发跨节点块传输 - 维护原子化:
DROP PARTITION自动级联使对应本地索引分区失效,无需全索引重建 - 统计可下推:支持
GRANULARITY => 'PARTITION',各分区独立收集,CBO 对局部谓词(如WHERE dt = DATE'2024-01-01')估算更准 - 隐式分区裁剪:只要查询条件含分区键,优化器自动排除无关本地索引分区,减少扫描量
改造成本地索引要注意的硬约束
不是所有全局索引都能无损替换,必须检查以下三点:
- 唯一性约束是否依赖全局索引:若业务要求跨分区唯一(如全表
order_id唯一),本地索引无法保证,需保留全局唯一索引或改用SEQUENCE + SHARDING KEY应用层控制 - 查询是否常跨分区范围扫描:如
WHERE create_time BETWEEN SYSDATE-30 AND SYSDATE,本地索引需合并扫描多个分区,而全局索引单次 B-tree 遍历即可——此时应评估实际执行计划中INDEX RANGE SCANvsINDEX RANGE SCAN PARTITION的一致性开销 - 分区键选择是否合理:本地索引必须和表使用相同分区键(
LOCAL ON (col)),若原表按MOD(id,4)分区但查询高频过滤status,则本地索引对status字段无效,需额外建非分区辅助索引
实操迁移步骤(最小停机)
以表 orders 和全局索引 idx_orders_custid 为例:
CREATE INDEX idx_orders_custid_local ON orders(cust_id) LOCAL;
然后逐个验证分区有效性:
SELECT index_name, partition_name, status FROM dba_ind_partitions WHERE index_name = 'IDX_ORDERS_CUSTID_LOCAL';
确认全部为 USABLE 后,再删除原全局索引:
DROP INDEX idx_orders_custid;
注意:DROP 本身不锁表,但若该索引被唯一约束依赖,需先 DISABLE CONSTRAINT 或重建约束指向新索引。
最易被忽略的是应用层绑定变量与分区键的耦合——即便建了本地索引,若 SQL 中 WHERE cust_id = :b1 但没带分区键条件,Oracle 仍要扫描所有分区索引段。这点比参数调优更影响实际效果。











