在传统的关系型数据库设计里,索引要么建在整张表上,要么不建,没有中间状态。对于一张按时间分区的海量数据表来说,这往往意味着两难的处境:历史分区的数据很少被访问,但为了几个活跃分区的查询性能,不得不给所有分区都建上索引,白白消耗大量存储空间,还拖慢了数据加载速度。Oracle 19c引入的Partial Indexing(部分索引)特性正是针对这个痛点,它允许同一个分区表上的索引只覆盖部分分区,被排除的分区上不持有任何索引结构。本文将从原理、语法、使用场景和维护操作几个方面,详细介绍这个特性的实际使用方法。

一、Partial Indexing的基本原理
部分索引的核心机制与分区表的索引类别绑定在一起。Oracle的分区索引分为本地索引(local index)和全局索引(global index),而Partial Indexing只能作用于本地索引。它通过在索引级别指定INDEXING FULL或INDEXING PARTIAL两种属性,配合每个分区自身的INDEXING ON或INDEXING OFF属性,共同决定索引最终覆盖哪些分区。
具体规则是这样的:当索引被定义为INDEXING PARTIAL时,Oracle会检查表上每个分区的INDEXING属性,只有标记为INDEXING ON的分区才会真正出现在索引结构中,标记为INDEXING OFF的分区则完全不占用索引空间。查询优化器在生成执行计划时也清楚这一规则,对于访问被排除分区的查询,它不会尝试使用这个部分索引,从而保证查询结果的正确性。这一点和不可见索引不同,不可见索引只是优化器看不见,但结构仍在维护;部分索引则是物理上就不存在,DML操作时自然也不需要维护它。
需要注意的是,如果一个索引定义为INDEXING FULL(默认值),那么无论分区怎么设置INDEXING属性,所有分区都会被索引覆盖。换句话说,分区的INDEXING属性只有在部分索引下才有意义,两者是配合使用的关系。
二、创建部分索引的完整语法示例
创建部分索引分两步:先在表或分区级别设置INDEXING属性,再创建索引时指定INDEXING PARTIAL。下面通过一个订单表的实际例子演示完整过程。
-- 创建分区表,历史分区关闭索引,近三个月分区开启索引
CREATE TABLE t_orders (
order_id NUMBER,
order_date DATE,
customer_id NUMBER,
amount NUMBER
)
PARTITION BY RANGE (order_date)
(
PARTITION p_202301 VALUES LESS THAN (DATE '2024-01-01') INDEXING OFF,
PARTITION p_202401 VALUES LESS THAN (DATE '2024-02-01') INDEXING OFF,
PARTITION p_202402 VALUES LESS THAN (DATE '2024-03-01') INDEXING ON,
PARTITION p_202403 VALUES LESS THAN (DATE '2024-04-01') INDEXING ON,
PARTITION p_max VALUES LESS THAN (MAXVALUE) INDEXING ON
);
-- 创建部分索引,只覆盖INDEXING ON的分区
CREATE INDEX idx_orders_cust ON t_orders (customer_id)
INDEXING PARTIAL
TABLESPACE idx_ts;
-- 验证索引状态
SELECT index_name, indexing, partitioned
FROM user_indexes
WHERE table_name = 'T_ORDERS';
如果表已经存在,也可以事后修改分区的索引属性。比如数据归档后想把某个分区排除出索引,使用ALTER TABLE ... MODIFY PARTITION语句即可,此时该分区上的索引段会被删除,空间立即释放。反向操作同理,把某个分区改成INDEXING ON后,需要在对应分区上重建部分索引,Oracle才会为新纳入的分区补建索引结构。
-- 将旧分区排除出部分索引,释放其索引空间 ALTER TABLE t_orders MODIFY PARTITION p_202401 INDEXING OFF; -- 将归档后重新需要查询的分区纳入部分索引,需重建 ALTER TABLE t_orders MODIFY PARTITION p_202402 INDEXING ON; ALTER INDEX idx_orders_cust REBUILD PARTITION p_202402;
还有一种常见做法是在表级别设置默认属性,新建分区自动继承。比如ALTER TABLE t_orders SET INDEXING ON之后,后续自动分区拆分产生的新分区默认都会带上INDEXING ON属性,避免遗漏。
三、适用场景与性能收益分析
部分索引最适合的场景是典型的冷热数据分离业务。以日志表、订单表为例,查询请求绝大多数集中在最近三到六个月的数据上,历史分区一年也访问不了几次。在这种分布下,使用部分索引可以把索引存储压缩到原来的百分之十几,同时大幅减少批量加载和删除历史数据时的索引维护开销,因为被排除的分区在写入时完全不需要更新索引。
从查询性能角度看,只要SQL的谓词条件能够被分区裁剪(partition pruning)限定在带索引的分区范围内,优化器就会正常使用部分索引,执行计划和普通本地索引没有区别。但如果查询范围跨过了冷热边界,比如统计全年数据,优化器会放弃部分索引改走全表扫描或分区全扫。因此在使用前一定要梳理清楚业务的查询模式,确认高频查询都落在热数据区间内。
另一个需要注意的点是执行计划的解读。通过DBMS_XPLAN查看部分索引相关计划时,操作名称会显示为PARTITION RANGE结合索引访问的组合,同时在INDEX提示后面能看到分区裁剪信息。监控方面,数据字典视图USER_IND_PARTITIONS中的STATUS列会显示USABLE或UNUSABLE,被排除的分区在该视图中不产生记录,可以用这一点来核对索引覆盖情况。
-- 查看部分索引实际覆盖的分区 SELECT partition_name, status FROM user_ind_partitions WHERE index_name = 'IDX_ORDERS_CUST'; -- 对比空间占用:部分索引 vs 全表索引 SELECT segment_name, SUM(bytes)/1024/1024 AS size_mb FROM user_segments WHERE segment_name LIKE 'IDX_ORDERS%' GROUP BY segment_name;
四、使用限制与维护注意事项
部分索引虽然好用,但限制条件要记牢。首先它只支持本地分区索引,全局索引上无法使用INDEXING PARTIAL子句。其次,分区的INDEXING属性一旦设置,主键约束、唯一约束使用的索引同样会受到影响,如果唯一性约束依赖的列包含在分区键中则没有问题,否则需要谨慎评估。位图索引同样支持部分索引属性,但组合使用时要注意数据仓库场景下的并发限制。
维护层面的一个关键操作是切换分区时的行为。当使用EXCHANGE PARTITION和数据泵导入导出时,部分索引的属性会随分区元数据一起处理,交换进来的分区如果INDEXING属性不匹配,索引可能变为UNUSABLE状态,需要手动重建。另外,使用GoldenGate或Data Guard的逻辑复制环境时,建议在目标端提前确认部分索引的定义策略,避免主备两端索引覆盖范围不一致带来的性能差异。
最后给出一个实用的选型建议:如果你的表数据量在千万级以上、按时间或其他低频访问维度分区、且查询明显集中在部分分区,那么Partial Indexing基本都值得尝试。可以先在测试环境用真实数据建立对比索引,通过DBMS_XPLAN和段空间统计验证收益,再推广到生产环境。对于小表或者查询模式均匀分布在全表的业务,普通全表索引依然是更简单直接的选择。
Oracle 19cPartial Indexing部分索引修改时间:2026-09-08 00:30:36