Oracle采用GENERATED BY DEFAULT ON NULL AS IDENTITY能否共享跨表ID池
核心问题直接答复
Oracle中通过GENERATED BY DEFAULT ON NULL AS IDENTITY定义的自增ID字段,哪怕不同表的ID字段名称完全相同,也无法实现共享同一个ID取值池的效果。
本质原因很简单:每创建一个IDENTITY类型的字段,Oracle都会在后台自动生成一个与该字段强绑定的隐式专属序列,序列的取值规则完全按照字段定义的参数生成,和其他表的IDENTITY列没有任何关联。
就拿给出的两个建表示例来说:TEST和TEST2的ID列虽然都命名为ID、都设置为从1开始自增,但是两个表各自的ID列背后绑定了独立的专属序列,两个表各自插入10条数据的话,两边的ID都会生成1到10的连续值,完全重复,不存在跨表共享取号的逻辑。
多表共享全局ID池的可靠实现方案
要从机制上保证所有表的ID永远不会重叠,最稳妥的方案是用显式创建的全局公共序列替代表自带的隐式IDENTITY序列,操作步骤如下:
- 第一步:创建全实例统一的共享序列,按照业务需要设置取号规则即可,示例语句:
-- 共享序列配置说明:nocycle保证序列不会循环取值,从根源上避免重号;cache值可根据业务并发调整 CREATE SEQUENCE SHARED_GLOBAL_ID START WITH 1 INCREMENT BY 1 NOCYCLE NOORDER CACHE 100; - 第二步:调整原有两个表的ID字段定义,去掉原有的IDENTITY属性,将字段默认值指向这个共享序列的取值,整个过程不需要删除表、清空原有数据,直接通过alter语句修改即可:
-- 修改TEST表的ID列,绑定共享序列默认值 ALTER TABLE TEST MODIFY ID INTEGER DEFAULT SHARED_GLOBAL_ID.NEXTVAL NOT NULL; -- 修改TEST2表的ID列,绑定共享序列默认值 ALTER TABLE TEST2 MODIFY ID INTEGER DEFAULT SHARED_GLOBAL_ID.NEXTVAL NOT NULL; - 调整完成后,不管向TEST还是TEST2表插入数据,只要没有手动指定ID值,就会自动从同一个共享序列中取号,从机制上保证两个表生成的ID永远不会重叠。
需要明确的是:如果试图保留原有的IDENTITY列语法,强制让两个表的IDENTITY字段共享取号逻辑,是无法实现的。Oracle不支持修改系统为IDENTITY列自动生成的隐式序列的绑定关系,这类系统管理的序列是和字段绑定的专属对象,无法被多个表的IDENTITY列复用。
对现有临时分段号方案的风险提示
当前采用的“给不同表设置不同起始值划分独立号段”的方案,长期落地存在三个明确的风险:
- 当单个表的自增值跑入其他表的预设号段范围时,会直接触发主键唯一约束冲突,这类跨表的ID冲突故障排查成本极高。
- 后续新增带自增ID的表时,需要手动维护号段分配规则,随着表数量增多,号段分配错误的概率会持续上升。
- 固定划分的号段会造成ID空间的浪费,不同表删除数据后腾出的ID值无法被其他表复用,整体ID空间利用率极低。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

