组合分区适合同时按时间范围和离散维度(如地域、类别)高频查询的场景;典型如销售数据既查月度趋势又查区域表现,通过range-list或range-hash实现两级剪枝优化。

组合分区适合什么查询场景
组合分区(Composite Partitioning)本质是「先按主维度粗筛,再按次维度细切」,典型用于同时高频查询多个字段、且字段间存在天然层级关系的场景。比如销售数据既常按sale_date查月度趋势,又常按region或product_category查区域/品类表现——单用范围分区或列表分区都只能优化其中一维,而组合分区能兼顾两者。
但注意:它不是万能加速器。如果查询只过滤region不带时间条件,或者只查单个product_id这种高基数点值,组合分区反而可能因分区过多、剪枝失效而变慢。
Range-List 和 Range-Hash 的选型差异
Oracle 主要支持两种组合方式:RANGE-LIST 和 RANGE-HASH,区别不在语法,而在数据分布与查询模式匹配度:
-
RANGE-LIST:主分区按时间/数值范围(如sale_date),子分区按离散枚举值(如region IN ('East','West','North'))。适合次维度取值固定、数量可控( -
RANGE-HASH:主分区仍为范围,子分区按哈希函数打散(如MOD(product_id, 8))。适合次维度取值多、分布广、无明确分类逻辑的字段,比如用户ID、订单号,目标是让每个子分区数据量尽量均匀。
别硬套模板。例如把product_id强行塞进LIST子分区,一旦新增品类就要改DDL,运维成本陡增;反过来,用HASH分region,会导致同一地区数据被拆到多个子分区,聚合查询时无法跳过无关子分区。
确保子分区真正参与剪枝的关键写法
组合分区的剪枝分两级:先裁主分区(靠PARTITION START/STOP KEY),再裁子分区(靠SUBPARTITION KEY)。但第二级剪枝极易失效,常见原因:
- WHERE 中对子分区键用了函数,比如
UPPER(region) = 'EAST'—— 子分区键变成非确定性表达式,Oracle 放弃子分区裁剪。 - 子分区键类型隐式转换,比如
region是VARCHAR2(20),但查询写成region = 101(数字),触发隐式转字符串,破坏匹配。 - 使用了绑定变量且未指定精确类型,导致优化器无法在硬解析阶段确认子分区范围。
验证是否生效,必须看执行计划里有没有 SUBPARTITION LIST SINGLE 或 SUBPARTITION RANGE SINGLE 这类字样。只看到 PARTITION RANGE SINGLE,说明子分区没剪掉,白建了。
局部索引必须按子分区对齐
在组合分区上建索引,LOCAL 是默认且推荐选项,但关键细节在于:局部索引的分区粒度必须和表的子分区完全一致。否则会出现两种后果:
- 索引子分区数 ≠ 表子分区数:插入数据时报
ORA-14035: invalid subpartition name; - 索引定义中漏写
SUBPARTITION模板,导致 Oracle 自动按主分区粒度建索引段,后续子分区剪枝时索引扫描仍需跨多个索引段,性能归零。
正确写法示例(RANGE-LIST):
CREATE INDEX idx_sales_region_dt ON sales_table(region, sale_date)
LOCAL (
SUBPARTITION sp_east VALUES ('East'),
SUBPARTITION sp_west VALUES ('West'),
SUBPARTITION sp_north VALUES ('North'),
SUBPARTITION sp_other VALUES (DEFAULT)
);
漏掉任意一个 SUBPARTITION 定义,或者把 VALUES 写成范围值,都会让局部索引失去子分区感知能力。
组合分区真正的难点不在创建,而在长期运行中子分区键值分布偏斜、新增枚举值未同步更新子分区定义、或统计信息未覆盖子分区层级——这些细节不显眼,但会悄悄让剪枝率从95%掉到30%。











