根本解法是主库序列禁用ORDER并增大CACHE:必须执行ALTER SEQUENCE … NOORDER且CACHE≥1000,因ORDER在RAC中引发单点DFS锁争用,而ADG备库MRP串行重放会放大该问题导致日志堆积和应用延迟。
oracle 12c adg环境下,序列号缓存冲突不是adg本身的问题,而是rac主库侧的enq: sq - contention在备库启用实时应用(mrp)后被放大暴露——根本解法不在adg配置,而在主库序列是否用了noorder和足够大的cache。
为什么ADG备库会“感知”到主库的序列争用
ADG备库的MRP进程是单线程串行应用归档日志的,它不生成新序列值,但会忠实重放主库已产生的所有DML。当主库因CACHE=20 + ORDER导致大量NEXTVAL请求卡在DFS锁上时,这些SQL实际执行时间被拉长、事务提交变慢,进而使归档日志生成节奏紊乱、日志堆积、MRP追赶延迟升高。你看到的“备库慢”,其实是主库序列设计缺陷的下游反射。
- MRP不会报
enq: SQ - contention,但它日志里会出现WAIT_FOR_GAP或APPLYING_LOG但SEQUENCE#长期不递增——这是主库出问题的信号灯 - 查
V$MANAGED_STANDBY发现RFS接收正常但MRP0卡住,大概率是主库端日志写入不连续,源头常为序列争用引发的事务阻塞 - ADG本身对序列无特殊处理逻辑;它只管日志流,不关心序列怎么生成
必须禁用ORDER,且CACHE至少设为1000
ORDER在RAC+ADG组合下是性能毒药:它强制所有实例的NEXTVAL请求路由到同一节点(通常是第一个启动的实例),该节点瞬间成为单点瓶颈,DFS锁排队雪崩。而ADG备库的MRP又无法并行化解这种串行化压力,只能被动等待。
- 立刻执行:
ALTER SEQUENCE your_seq NOORDER;—— 即使已存在,也需显式覆盖(ORDER是创建时默认隐含行为,不能靠“没写就等于没开”) -
CACHE值必须结合QPS估算:若每秒取号500次,CACHE=20撑不过50ms;建议起步CACHE=1000,高并发场景直接CACHE=5000 - 执行
ALTER SEQUENCE your_seq CACHE 5000 NOORDER;后,务必查DBA_SEQUENCES确认CACHE_SIZE和ORDER_FLAG(N表示NOORDER)已生效
别在ADG备库上建序列,更别试图“同步”主备序列状态
ADG物理备库是只读的,任何CREATE SEQUENCE或ALTER SEQUENCE都会报ORA-16000(database open for read-only access)。有人想通过逻辑备库或触发器绕过,这违背ADG设计初衷,且引入严重一致性风险。
- 序列只存在于主库;备库通过日志重放间接“看到”其效果,无需、也不应干预其元数据
- 所谓“序列值在主备不一致”是误解——
CURRVAL是会话级变量,备库没有会话上下文,根本不维护CURRVAL;NEXTVAL值由主库生成并固化在日志中,重放即确定 - 如果业务依赖“绝对连续ID”,说明选错了技术方案:序列天生不保证连续,应改用应用层UUID或分段分配策略
验证是否真解决:盯紧两个指标
改完不是就结束了。真正有效的验证,是看这两个地方有没有掉下去:
- 主库上
GV$ENQUEUE_STAT中EQ_TYPE='SQ'的TOTAL_WAITS和AVERAGE_WAIT是否显著下降(降幅>90%) - 备库
V$MANAGED_STANDBY中MRP0的SEQUENCE#是否稳定递增,不再长时间停在某个值上 - 额外提醒:
GV$_SEQUENCES视图在RAC中显示各节点本地缓存剩余量,若某节点CACHE_SIZE - LAST_NUMBER + MIN_VALUE长期接近0,说明CACHE还是偏小
最易被忽略的一点:NOORDER不是“可选项”,是RAC环境的强制前提;而CACHE调大也不是“越大越好”,超过50000后实例崩溃丢号量会变得肉眼可见——平衡点得根据你的平均故障间隔和业务对跳号的容忍度来定。


















