Oracle 序列 Sequence 是什么?和自增主键有什么关系?
简化版
Oracle Sequence 是独立的序列对象,用来生成递增或按规则变化的数字,常用于主键。传统 Oracle 常用 sequence.nextval 生成 ID;较新版本也支持 identity column。Sequence 生成的值不保证连续,因为缓存、回滚、并发、实例故障都可能产生跳号,但它能保证按序列规则生成唯一值。
详细版
Sequence 常见用法:
CREATE SEQUENCE user_seq START WITH 1 INCREMENT BY 1 CACHE 20;
INSERT INTO users(id, name)
VALUES (user_seq.NEXTVAL, 'Tom');
关键点:
NEXTVAL获取下一个序列值;CURRVAL获取当前会话已取过的序列值;CACHE可以提升性能,但可能导致故障后跳号;- 事务回滚不会回收已取的序列值;
- Sequence 适合生成技术主键,不适合生成要求绝对连续的业务流水号。
如果业务要求发票号、单据号严格连续,要用专门的业务编号方案,而不能直接依赖普通 Sequence。
完整版教学
一、Sequence 为什么是独立对象
Oracle 传统上不像某些数据库那样只在列上写 AUTO_INCREMENT。它把序列号生成抽成独立对象:
CREATE SEQUENCE order_seq;
这让序列可以被多个表或多个语句使用,也可以独立配置缓存、步长、最大值、循环等属性。
二、NEXTVAL 和 CURRVAL 怎么用
常见插入:
INSERT INTO orders(id, amount)
VALUES (order_seq.NEXTVAL, 100);
如果当前会话已经调用过 NEXTVAL,可以用:
SELECT order_seq.CURRVAL FROM dual;
CURRVAL 不是全局当前最大值,而是当前会话最近一次拿到的值。会话没调用过 NEXTVAL 前,不能直接使用 CURRVAL。
三、为什么 Sequence 会跳号
Sequence 不保证连续。常见跳号原因:
- 事务拿到序列值后回滚;
- 使用缓存后数据库异常重启;
- 多会话并发取号;
- RAC 多实例缓存序列;
- 手动调整序列值。
例如事务 A 获取了 1001,随后回滚,1001 不会被重新发给别人。这样做是为了性能和并发安全。
四、Sequence 适合技术主键
技术主键的目标是唯一、稳定、方便关联,不要求业务连续。Sequence 很适合这种场景。
但业务流水号不同,例如发票号可能要求严格连续、可审计、不能跳号。此时如果直接用 Sequence,回滚或故障导致的跳号就会变成业务问题。
正确做法是区分:
- 技术 ID:用 Sequence 或 identity;
- 业务编号:用业务规则生成,配合状态、审计和补偿机制。
五、Identity column 和 Sequence 的关系
Oracle 后续版本支持 identity column,可以在列定义上声明自动生成值,使用上更接近其他数据库的自增列。
但从理解角度看,identity 仍然是数据库自动生成数字的机制,和 Sequence 思路相通。面试时可以说:传统 Oracle 常显式使用 Sequence,现代版本也可以用 identity 简化自增主键定义。
六、常见误区与追问
| 用途 | 能否用普通 Sequence | 原因 |
|---|---|---|
| 技术主键 ID | 适合 | 只要求唯一稳定,不要求连续 |
| 发票号、监管流水 | 不宜直接用 | 通常要求连续、审计、可解释 |
| 高并发取号 | 适合配 CACHE | 性能好但可能跳号 |
易错点:Sequence 保证按规则发唯一值,不保证没有空洞。把“唯一递增”和“严格连续”混为一谈,是这题最常见的坑。
数字例子:CACHE 20 时,实例可能一次缓存 20 个号。已经缓存到 1001 到 1020,如果数据库在只用到 1005 时异常重启,1006 到 1020 可能就丢失不用;再启动后可能从 1021 继续。事务回滚也一样,拿到 1005 后回滚,1005 不会退回给别人。
- 误区:Sequence 生成的值一定连续。 回滚、缓存、故障、RAC 多实例都可能造成跳号。
- 误区:CURRVAL 是全库当前最大序列值。
CURRVAL是当前会话最近一次NEXTVAL的值,未调用过NEXTVAL不能直接用。 - 误区:Sequence 只能给一张表用。 Sequence 是独立对象,可以被多个语句或表引用,但是否共享要看业务设计。
- 追问:CACHE 为什么会导致跳号? 缓存值在内存中,实例异常后未使用的缓存号可能丢失,但换来更少的取号开销。
- 追问:Identity column 和 Sequence 有什么关系? Identity 是更接近自增列的声明方式,底层思想仍是数据库生成数字,传统 Oracle 常显式用 Sequence。
- 追问:严格连续业务号怎么做? 要单独设计业务编号、状态、审计、作废和补偿机制,不能直接依赖普通 Sequence。
七、加强记忆
Oracle Sequence 记住“独立取号器”:NEXTVAL 取下一个值,回滚不退号,缓存会提升性能但可能跳号。它适合技术主键,不适合要求绝对连续的业务单据号;连续编号要单独设计业务编号体系。