引用分区要求父表必须是分区表且外键列严格匹配其分区键,子表需显式声明外键并用partition by reference绑定该约束,否则建表失败;维护时删/截断/拆分父分区会自动下推至子表,但加分区不会触发子表同步。
oracle 12c 的引用分区(reference partitioning)不是“级联分区”,它不自动同步子表分区结构变更,而是让子表复用父表的分区逻辑——必须显式建外键、且外键列必须是父表的分区键,否则建表直接报错。
创建引用分区前必须满足的硬性条件
引用分区依赖已有父子关系,不是靠语法“开启”就能生效。关键约束有三个:
- 父表必须已是分区表(如
RANGE、LIST或HASH),且分区键是主键或唯一键的一部分 - 子表建表时必须通过
FOREIGN KEY ... REFERENCES显式声明外键,且该外键列**完全匹配**父表的分区键列(列名、类型、顺序、长度都得一致) - 子表建表语句中必须写明
PARTITION BY REFERENCE,并指定那个外键约束名,例如PARTITION BY REFERENCE (fk_child_parent)
漏掉任意一条,CREATE TABLE 都会失败,典型错误是 ORA-14035: invalid partition key specified for reference partitioning 或 ORA-14650: table referenced in reference partitioning is not partitioned。
引用分区建表语句怎么写才不出错
以订单(orders)和订单项(order_items)为例,常见错误写法是只建外键却不绑定分区逻辑,或外键列类型与父表不一致:
CREATE TABLE orders ( order_id NUMBER PRIMARY KEY, order_date DATE ) PARTITION BY RANGE (order_date) ( PARTITION p_2025_q1 VALUES LESS THAN (DATE '2025-04-01'), PARTITION p_2025_q2 VALUES LESS THAN (DATE '2025-07-01') ); <p>-- ✅ 正确:外键列 order_id 不是分区键 → 报错!必须用 order_date -- ❌ 错误示例(外键指向非分区键) ALTER TABLE order_items ADD CONSTRAINT fk_oi_order FOREIGN KEY (order_id) REFERENCES orders(order_id);</p><p>-- ✅ 正确写法:外键必须指向父表的分区键(这里是 order_date) CREATE TABLE order_items ( item_id NUMBER, order_id NUMBER, order_date DATE, -- 必须存在且类型严格一致 amount NUMBER, CONSTRAINT fk_oi_order FOREIGN KEY (order_date) REFERENCES orders(order_date) ) PARTITION BY REFERENCE (fk_oi_order);</p>
注意:order_date 在子表里不是主键,但必须存在、不可为空、类型与父表完全一致(比如不能一个是 DATE,一个是 TIMESTAMP)。
引用分区后,分区维护操作如何传递
引用分区的价值在于“维护动作自动下推”,但仅限于特定操作:
-
ALTER TABLE orders DROP PARTITION p_2025_q1→ 对应的order_items分区也自动删除(数据连带清除) -
ALTER TABLE orders TRUNCATE PARTITION p_2025_q2→ 子表对应分区数据也被清空 -
ALTER TABLE orders SPLIT PARTITION ...→ 子表对应分区也会被拆分 - 但
ADD PARTITION不会自动触发子表加新分区——子表分区是惰性创建的,只有插入数据落到新分区范围时,Oracle 才自动建对应子分区
也就是说,引用分区的“级联”是单向、被动的:父表删/截断/拆分 → 子表响应;但父表加分区 → 子表不响应,直到有数据写入才生成。
为什么物化视图刷新常在这里报 ORA-02291
当子表是引用分区,又建了 REFRESH FAST ON COMMIT 物化视图时,容易触发 ORA-02291: integrity constraint violated - parent key not found,根本原因不是数据缺失,而是:
- MV 定义里只写了子表(如
order_items),没把父表orders一起包含进去 - Oracle 刷新时按外键去查父表数据,但 MV 中根本没有
orders表,自然找不到对应order_date - 即使你加了
WHERE order_date >= ...过滤子表分区,只要外键列值在 MV 结果集中“不完整”,约束检查就失败
解决办法只有两个:要么把父表显式加入 MV 查询(SELECT ... FROM order_items JOIN orders USING (order_date)),要么放弃 ON COMMIT,改用 ON DEMAND 并手动控制刷新顺序——先刷父表 MV,再刷子表 MV。
引用分区真正省力的地方在于 DDL 维护,而不是 DML 逻辑透明;一旦涉及物化视图、导出导入、备份恢复等场景,外键列的数据一致性仍需人工对齐,这点很容易被忽略。











