主备切换后序列号不一致是必然现象,因data guard不复制序列内存状态,新主库序列值远小于表最大id,须用alter sequence increment by临时调整步长并推进至目标值后恢复为1。

主备切换(Switchover)后序列号“跳号”,本质是新主库上 SEQ.NEXTVAL 返回值远小于表中已有最大 ID,插入时直接报 ORA-00001: unique constraint violated。这不是序列“坏了”,而是 Oracle Data Guard 的复制机制与序列对象特性共同导致的必然现象——必须手动干预,否则业务无法继续。
为什么Data Guard不复制序列当前值
Data Guard 物理复制只同步数据块、控制文件和归档/在线日志,SEQUENCE 的当前状态(CURRVAL 和内存中的 NEXTVAL 计数器)不落盘、不进重做流,也不被 MRPs 应用。原主库可能已通过上万次 NEXTVAL 走到 12000,但原备库在只读/恢复模式下从不执行 NEXTVAL,它的序列仍停在初始值或最后一次显式调用的位置(比如 500)。角色一换,这个“500”就变成新主库的起点。
- 查不到错误日志,因为这不是故障,是设计如此
-
V$SEQUENCE或DBA_SEQUENCES里看不到“当前值”,只有LAST_NUMBER(数据字典快照值,不实时) - 备库即使开了
CACHE,只要没被激活为主库并执行过NEXTVAL,缓存段就从未加载进内存
常见报错和误判信号
刚切完就出问题,往往不是配置漏了,而是没意识到序列已失效:
-
SELECT seq_t1.currval FROM dual报ORA-08002:说明当前会话根本没调过NEXTVAL,不是序列坏了,是压根没初始化 -
INSERT INTO t1(id, name) VALUES(seq_t1.nextval, 'x')插入成功,但查表发现 ID = 501,而SELECT MAX(id) FROM t1是 11999:主键冲突马上就会来 - 应用日志里反复出现
ORA-00001,但建表语句、索引、约束都确认无误——八成是序列没对齐
ALTER SEQUENCE increment by 是唯一安全解法
不能删重建(会中断所有依赖它的触发器、包、视图),也不能靠 CURRVAL 补漏(它只返回本会话已取的值)。唯一可行路径是用 INCREMENT BY 临时“跳转”:
- 先算目标值:
SELECT NVL(MAX(id), 0) FROM t1→ 得到 11999,那下次NEXTVAL必须 ≥ 12000 - 再算步长:
ALTER SEQUENCE seq_t1 INCREMENT BY 11999 - seq_t1.nextval + 1(假设当前nextval是 500,就设为 11500) - 强制推进:
SELECT seq_t1.nextval FROM dual→ 返回 12000 - 立刻还原:
ALTER SEQUENCE seq_t1 INCREMENT BY 1 - 如果序列定义了
MINVALUE或CYCLE,调整前务必先ALTER SEQUENCE ... NOCYCLE,否则可能意外回绕
容易被忽略的验证盲区
执行完 ALTER SEQUENCE 不代表万事大吉。很多人只跑一遍 SELECT seq_t1.nextval 就去上线,结果第一次插入成功,第二次又崩了:
- 必须执行两次
SELECT seq_t1.nextval FROM dual,确认返回的是 12000 和 12001(验证递增性) - 真正插一条记录:
INSERT INTO t1(id, name) VALUES(seq_t1.nextval, 'verify'),再查是否为 12002 - 检查
DBA_SEQUENCES.cache_size:若仍为较大值(如 100),下次实例异常重启还会跳,建议非关键序列调小到 10–20 - RAC 环境下,确保所有节点都完成切换且未残留旧连接;残留会话可能还在用老序列缓存
序列值永远无法“追平”历史,能做的只是让下一次开始不冲突。最危险的不是跳号本身,是以为它会自动修复。











