全局分区索引支持全表唯一性,局部索引仅保证分区内部唯一;全局索引可对非分区键字段建唯一约束,12c+支持UPDATE GLOBAL INDEXES在线维护,避免索引失效。
全局分区索引能支持全表唯一性,局部索引不能
oracle 局部索引(local)的每个索引分区只覆盖对应表分区的数据,因此它只能保证“单个分区内的唯一性”。如果你建了 create unique index idx_local on sales(customer_id) local,而 customer_id = 123 出现在两个不同分区里,oracle 不会报错——因为这两个值分属不同索引分区,彼此不校验。
全局分区索引(GLOBAL PARTITION BY RANGE 或 GLOBAL PARTITION BY HASH)则把所有分区的数据统一组织进一个逻辑索引结构中。只要索引键(如 customer_id)被设为唯一,Oracle 就会在整个索引范围内查重,真正实现全表唯一约束。
- 局部索引要支撑唯一约束,必须把分区键也包含在索引列中,例如
CREATE UNIQUE INDEX idx_local ON sales(sale_date, customer_id) LOCAL—— 这意味着业务上无法仅靠customer_id做唯一校验 - 全局索引允许你对非分区键字段(如 ID、手机号、订单号)直接建唯一约束,且不强制绑定分区键
- DDL 约束定义时,
ALTER TABLE sales ADD CONSTRAINT uk_customer_id UNIQUE(customer_id)背后隐式依赖的是全局索引;若只有局部索引,这条语句会直接报错ORA-14036: partitioned index must include partitioning columns in unique/primary key
UPDATE GLOBAL INDEXES 在 12c+ 中已稳定支持,失效风险可控
很多人回避全局索引,是因为怕 DROP PARTITION 或 EXCHANGE PARTITION 导致索引变 UNUSABLE。但在 Oracle 12c 及之后版本,UPDATE GLOBAL INDEXES 已成为可靠选项,且行为更确定:
- 执行
ALTER TABLE sales DROP PARTITION p_2025q1 UPDATE GLOBAL INDEXES,Oracle 会在线清理该分区在全局索引中的条目,索引全程保持VALID - 相比重建(
ALTER INDEX idx_global REBUILD),它避免了全量扫描和排序,耗时从小时级降到分钟级(尤其对百亿行表) - 注意:该子句要求足够临时表空间,并会延长 DDL 执行时间——不是零成本,但可预测、可监控
- 漏加
UPDATE GLOBAL INDEXES后,索引状态变为UNUSABLE,后续任何涉及该索引的查询或 INSERT 都会报ORA-01502,这点必须写入运维 checklist
局部索引无法用于跨分区唯一校验场景
当业务要求“全表维度唯一”,比如用户注册手机号、交易流水号、设备序列号,这些字段与时间/地域等分区键无关,也不应被人为拆散到各分区独立管理。此时局部索引本质是错配:
- 即使强行用局部索引 + 分区键组合(如
(phone_no, region_code)),也无法防止同一手机号在不同region_code下重复注册 - 应用层做分布式唯一校验(如 Redis set + DB 写入)会引入一致性风险和额外延迟
- 全局索引天然适配这种“键值全局唯一”语义,且 Oracle 的唯一性检查是原子的、事务一致的
- 12c 引入的部分索引(
PARTIAL INDEX)可进一步优化:对历史冷分区建全局索引,对高频写入的新分区暂时禁用索引段,兼顾唯一性与写入性能
容易忽略的锁与并发细节
全局索引维护期间的锁粒度比局部索引高,这是代价,但不是不可控的陷阱:
-
UPDATE GLOBAL INDEXES对全局索引本身加DX(死锁检测)锁,而非表级排他锁,不影响其他分区的 DML - 局部索引在
TRUNCATE PARTITION时虽不失效,但其唯一性约束仍受限于分区边界——这点常被误认为“安全”,实则埋下数据异常隐患 - OLTP 场景下,如果唯一字段更新频繁(如用户修改手机号),全局索引的 B-tree 争用可能高于局部索引;此时需结合
NOLOGGING、PCTFREE和并行 DML 缓解
真正关键的不是“该不该用全局索引”,而是确认业务是否真需要跨分区唯一性——一旦需要,局部索引再易维护也解决不了根本问题。











