是的,在 Oracle 数据库中,分区表的主键必须显式包含分区键,否则在创建表时会直接报出 ORA-14038 错误。原因其实很明确:局部索引无法跨分区保证全局唯一性。也就是说,如果主键中没有分区键,那么同一个主键值就可能在不同分区里重复出现。

没错,Oracle 分区表的主键必须明确包含分区键,否则建表时就会触发 ORA-14038 错误。这并不是简单的规范建议,而是 Oracle 在分区表设计中的强制校验规则。
为什么 CREATE TABLE 会报 ORA-14038
Oracle 要求主键或任意唯一约束的列集合必须“覆盖”分区键,也就是说,分区键列必须包含在主键列中。核心原因在于局部索引(LOCAL)本身存在语义限制:
- 如果主键没有包含分区键(例如分区键是
create_time,而主键只定义为id),那么相同的id值就可能分布在多个分区中 LOCAL本地索引只能在单个分区范围内保证唯一性,无法完成跨分区的全局唯一性校验- 为了避免主键唯一性语义被破坏,Oracle 会在建表阶段直接拒绝这种设计
哪些主键写法能通过 Oracle 校验
只要主键列组合能够保证“主键值 + 分区键”可以唯一定位一条记录,这种定义就是合法的。常见可通过校验的写法包括:
PRIMARY KEY (dt)—— 直接以分区键作为主键,适合按时间维度建模的场景PRIMARY KEY (dt, id)—— 分区键加业务主键列,是 Oracle 分区表中最常见、最通用的方案PRIMARY KEY (year, month, id)—— 如果分区键是复合列(year, month),那么主键中必须同时包含这两列(顺序可以不同)
需要注意的是:USING INDEX LOCAL 不能脱离主键定义单独解决问题,必须与以上合法主键写法配合使用;即使尝试通过声明 GLOBAL 全局索引来规避限制,Oracle 依然会要求唯一约束相关索引键包含分区键,本质上仍然无法绕过这一规则。
OceanBase 和 MySQL 的行为差异要小心
虽然这里讨论的是 Oracle 分区表主键规则,但在数据库迁移、兼容改造或混合部署过程中,这类差异非常容易成为踩坑点:
- OceanBase(Oracle 模式)同样会强制要求:分区键必须是主键的子集,否则也会直接报错
- MySQL 分区表也有类似限制,要求分区键必须属于主键的一部分,否则会报
ERROR 1503 - 不过 OceanBase 对无主键表更宽松,允许任意列作为分区键;而 Oracle 对无主键表不支持分区,严格来说,Oracle 不允许创建没有主键的分区表
Reference Partitioning 场景下外键怎么设
在级联分区场景中,例如子表通过外键引用父表时,外键列必须对应父表的分区键,不能引用父表主键中的其他非分区列:
- ❌ 错误:
FOREIGN KEY (order_id) REFERENCES orders(order_id)(order_id不是分区键) - ✅ 正确:
FOREIGN KEY (order_date) REFERENCES orders(order_date)(order_date是父表分区键,且字段类型必须严格一致)
这一点在 Oracle Reference Partitioning 中非常容易被忽视,进而导致 CREATE TABLE order_items 直接失败。由于报错信息通常不够直观,排查时应重点核对外键列是否与父表分区键完全一致。
