Local索引必须与分区键对齐,因其本质是“每个分区一张索引”,物理上绑定对应表分区,故建索引时必须包含且顺序一致于分区键全部列,否则无法保证查询精准下推至单一分区。

Local 索引为什么必须和分区键对齐
Local 索引本质是“每个分区一张索引”,物理上和对应表分区一一绑定。这意味着 CREATE INDEX ... LOCAL 时,Oracle(或 PostgreSQL 分区索引等效实现)会强制要求索引键**必须包含分区键的全部列**,且顺序需一致——否则无法保证查询能精准下推到单个分区。
常见错误现象:ORA-14035: invalid partition key specified for local index 或建索引时提示“partitioning column not in index key”。
- 若按
sale_date范围分区,local 索引必须以sale_date开头(如INDEX(sale_date, product_id)),不能只建INDEX(product_id) - 即使业务常查
product_id,也要接受前导列冗余;否则只能选 global - 好处是分区维护(如
DROP PARTITION)时 local 索引自动失效对应片段,不锁全表
Global 索引适合高频非分区键查询但代价高
Global 索引是跨分区的单个 B-tree,支持任意列组合建索引,无需包含分区键——这正是它灵活的地方。但灵活性换来的是维护成本:任何分区 DDL(ALTER TABLE ... DROP/EXCHANGE PARTITION)都会使整个 global 索引失效,必须显式 ALTER INDEX ... REBUILD 或加 UPDATE GLOBAL INDEXES 子句(Oracle 12c+)。
- 典型场景:用户按
user_id频繁查询,而表按create_time分区,此时GLOBAL INDEX(user_id)是合理选择 - 注意
UPDATE GLOBAL INDEXES会延长 DDL 执行时间,且重建期间索引不可用,需评估窗口期 - PostgreSQL 中无原生 global 索引概念,需用普通 B-tree 索引 + 分区约束下推,效果类似但无自动失效机制
执行计划里怎么看索引是否真正生效
光看 EXPLAIN 显示用了某个索引不够,关键要确认是否发生分区裁剪(partition pruning)和索引范围扫描是否落到具体分区。Oracle 中重点关注 PARTITION RANGE SINGLE 或 ALL,以及 INDEX RANGE SCAN 的 object_name 是否带分区后缀(如 IX_LOG_2024Q1)。
- Local 索引命中时,执行计划通常出现
PARTITION RANGE SINGLE+INDEX RANGE SCAN,且OBJECT_NAME是子分区名 - Global 索引即使走索引,也可能显示
PARTITION RANGE ALL或无分区信息,因为索引本身不分区 - 用
DBMS_XPLAN.DISPLAY_CURSOR查真实执行统计,比EXPLAIN PLAN更准,尤其涉及绑定变量时
混合策略:一个表上 local 和 global 索引可以共存
没有“只能选一种”的限制。实际中常见组合:用 local 索引支撑分区键高频过滤(如按天查日志),再加 1–2 个 global 索引支撑核心业务维度(如订单号、客户 ID)。但要注意索引总数影响 DML 性能——每次 INSERT/UPDATE 都要维护所有相关索引。
- local 索引数量 = 分区数 × 1(每个分区一份),global 索引数量 = 1(全局一份)
- 如果分区数达上百,local 索引的元数据开销和收集统计信息耗时明显上升,
DBMS_STATS.GATHER_TABLE_STATS需指定GRANULARITY => 'PARTITION'分批处理 - global 索引越多,
DROP PARTITION后重建越慢;建议把 global 索引控制在 3 个以内,优先保最关键的查询路径










