如何构建跨分区高效查询的全局分区索引_GLOBAL PARTITION BY RANGE?

2026-04-29 01:122阅读0评论SEO资源
  • 内容介绍
  • 相关推荐

本文共计1085个文字,预计阅读时间需要5分钟。

如何构建跨分区高效查询的全局分区索引_GLOBAL PARTITION BY RANGE?

相关专题

GLOBAL PARTITION BY RANGE 不能直接创建在普通表上

oracle 中 global partition by range 只能用于本地索引(local)的“全局化”替代方案,但它本身不是一种独立的索引类型。你不能写 create index ... global partition by range 去直接建一个“全局范围分区索引”——语法会报错:ora-00922: missing or invalid option

真正能用上的,是「全局分区索引」(Global Partitioned Index),它必须基于已分区的表(即表本身是 RANGE / LIST / HASH 分区),且索引的分区键可以不同于表的分区键。

  • 表必须先按某种策略分区(例如按 order_date RANGE 分区)
  • 全局索引需显式声明 GLOBAL PARTITION BY RANGE,并指定自己的分区列(如 customer_id
  • 全局索引的分区数、边界必须手动定义,不继承表的分区结构

建全局分区索引前必须确认表已分区

如果表没分区,CREATE INDEX ... GLOBAL 会失败,报错:ORA-14038: GLOBAL partitioned index must be created on a partitioned table。这不是权限或语法问题,是 Oracle 强制约束。

检查方式很简单:

SELECT partitioning_type, status FROM user_part_tables WHERE table_name = 'YOUR_TABLE';

  • 返回空行 → 表未分区,得先 ALTER TABLE ... SPLIT PARTITION 或重建为分区表
  • PARTITIONING_TYPERANGE / LIST / HASH → 可继续
  • 注意:即使表有子分区(composite),也算“已分区”,满足前提

GLOBAL PARTITION BY RANGE 的分区键必须可排序且稳定

你指定的索引分区列(比如 customer_id)会被用来划分全局索引的每个分区,它的值分布直接影响查询是否能走分区裁剪。如果选了一个高倾斜字段(如状态码 status IN (0,1)),会导致大部分数据挤在 1–2 个分区里,失去跨分区高效查询的意义。

  • 推荐用主键前缀、时间戳、或业务上均匀分布的数字型字段
  • 避免用 VARCHAR2 长文本或含大量 NULL 的列 —— 分区边界定义困难,且 MAXVALUE 边界对 NULL 处理不直观
  • 每个分区上限要预估:Oracle 要求所有分区键值必须落在显式定义的范围内,越界 DML 会报 ORA-14400: inserted partition key is outside specified partition

示例合法语句:

CREATE INDEX idx_global_cust ON orders(customer_id) GLOBAL PARTITION BY RANGE(customer_id) ( PARTITION p1 VALUES LESS THAN (10000), PARTITION p2 VALUES LESS THAN (20000), PARTITION pmax VALUES LESS THAN (MAXVALUE) );

全局分区索引维护成本高,DML 易阻塞

和本地索引不同,全局分区索引的任意分区都可能被单条 DML 影响(比如更新 customer_id)。这意味着:表的任何分区发生 UPDATEDELETE,只要涉及索引键变更,就可能触发跨分区锁,甚至导致整个索引不可用。

  • 表做 DROP PARTITIONTRUNCATE PARTITION 时,全局索引会 INVALID,必须加 UPDATE GLOBAL INDEXES 子句,否则操作失败
  • 批量插入若集中在某几个 customer_id 段,会争抢同一索引分区的 latch,出现 enq: TX - index contention
  • 重建时不能在线(ONLINE 不支持全局分区索引),停机窗口必须预留充足

所以,真要跨分区高效查,优先考虑本地索引 + 分区裁剪;只有当查询条件几乎总是落在索引分区键上(比如总按 customer_id BETWEEN ? AND ? 查),才值得承担全局索引的维护代价。

最常被忽略的一点:全局分区索引的统计信息必须定期收集,且要用 DBMS_STATS.GATHER_INDEX_STATS 单独跑,GATHER_TABLE_STATS 不会自动覆盖它 —— 缺失统计会导致 CBO 误判执行计划,反而变慢。

本文共计1085个文字,预计阅读时间需要5分钟。

如何构建跨分区高效查询的全局分区索引_GLOBAL PARTITION BY RANGE?

相关专题

GLOBAL PARTITION BY RANGE 不能直接创建在普通表上

oracle 中 global partition by range 只能用于本地索引(local)的“全局化”替代方案,但它本身不是一种独立的索引类型。你不能写 create index ... global partition by range 去直接建一个“全局范围分区索引”——语法会报错:ora-00922: missing or invalid option

真正能用上的,是「全局分区索引」(Global Partitioned Index),它必须基于已分区的表(即表本身是 RANGE / LIST / HASH 分区),且索引的分区键可以不同于表的分区键。

  • 表必须先按某种策略分区(例如按 order_date RANGE 分区)
  • 全局索引需显式声明 GLOBAL PARTITION BY RANGE,并指定自己的分区列(如 customer_id
  • 全局索引的分区数、边界必须手动定义,不继承表的分区结构

建全局分区索引前必须确认表已分区

如果表没分区,CREATE INDEX ... GLOBAL 会失败,报错:ORA-14038: GLOBAL partitioned index must be created on a partitioned table。这不是权限或语法问题,是 Oracle 强制约束。

检查方式很简单:

SELECT partitioning_type, status FROM user_part_tables WHERE table_name = 'YOUR_TABLE';

  • 返回空行 → 表未分区,得先 ALTER TABLE ... SPLIT PARTITION 或重建为分区表
  • PARTITIONING_TYPERANGE / LIST / HASH → 可继续
  • 注意:即使表有子分区(composite),也算“已分区”,满足前提

GLOBAL PARTITION BY RANGE 的分区键必须可排序且稳定

你指定的索引分区列(比如 customer_id)会被用来划分全局索引的每个分区,它的值分布直接影响查询是否能走分区裁剪。如果选了一个高倾斜字段(如状态码 status IN (0,1)),会导致大部分数据挤在 1–2 个分区里,失去跨分区高效查询的意义。

  • 推荐用主键前缀、时间戳、或业务上均匀分布的数字型字段
  • 避免用 VARCHAR2 长文本或含大量 NULL 的列 —— 分区边界定义困难,且 MAXVALUE 边界对 NULL 处理不直观
  • 每个分区上限要预估:Oracle 要求所有分区键值必须落在显式定义的范围内,越界 DML 会报 ORA-14400: inserted partition key is outside specified partition

示例合法语句:

CREATE INDEX idx_global_cust ON orders(customer_id) GLOBAL PARTITION BY RANGE(customer_id) ( PARTITION p1 VALUES LESS THAN (10000), PARTITION p2 VALUES LESS THAN (20000), PARTITION pmax VALUES LESS THAN (MAXVALUE) );

全局分区索引维护成本高,DML 易阻塞

和本地索引不同,全局分区索引的任意分区都可能被单条 DML 影响(比如更新 customer_id)。这意味着:表的任何分区发生 UPDATEDELETE,只要涉及索引键变更,就可能触发跨分区锁,甚至导致整个索引不可用。

  • 表做 DROP PARTITIONTRUNCATE PARTITION 时,全局索引会 INVALID,必须加 UPDATE GLOBAL INDEXES 子句,否则操作失败
  • 批量插入若集中在某几个 customer_id 段,会争抢同一索引分区的 latch,出现 enq: TX - index contention
  • 重建时不能在线(ONLINE 不支持全局分区索引),停机窗口必须预留充足

所以,真要跨分区高效查,优先考虑本地索引 + 分区裁剪;只有当查询条件几乎总是落在索引分区键上(比如总按 customer_id BETWEEN ? AND ? 查),才值得承担全局索引的维护代价。

最常被忽略的一点:全局分区索引的统计信息必须定期收集,且要用 DBMS_STATS.GATHER_INDEX_STATS 单独跑,GATHER_TABLE_STATS 不会自动覆盖它 —— 缺失统计会导致 CBO 误判执行计划,反而变慢。