<p>enq: SQ - contention 等待主因是 Sequence CACHE 过小且未设 NOORDER;RAC 下默认 CACHE 20 导致频繁争用 DFS 锁,ORDER 更加剧跨节点协调;应查 GV$_SEQUENCES 定位低 CACHE、ORDER=Y 的序列,合理调整 CACHE 与 NOORDER,并配合应用层批量取值。</p>

enq: SQ - contention 就是 Sequence CACHE 太小
Oracle RAC 中大量出现 enq: SQ - contention 等待,基本可以断定不是 SQL 写得差、也不是磁盘慢,而是 Sequence 的 CACHE 值太小且没设 NOORDER。默认建的 Sequence 是 CACHE 20,在 RAC 下每个实例最多缓存 20 个号——高并发时几毫秒就用光,接下来每次 NEXTVAL 都要抢着更新 seq$ 表、申请 DFS 锁、同步跨节点状态,锁全卡在同一个地方。
-
CACHE越小,号段耗尽越快,争用越密集 -
ORDER在 RAC 下会让问题雪上加霜:它强制全局有序,每次取值都要跨节点协调,本质是用性能换连续性 -
NOORDER是 RAC 必选项(除非业务真要求严格递增)
怎么快速定位拖后腿的 Sequence
别靠猜,直接查 GV$_SEQUENCES(RAC 必用,单机也能用 DBA_SEQUENCES):
SELECT SEQUENCE_OWNER, SEQUENCE_NAME, CACHE_SIZE, ORDER_FLAG FROM GV$_SEQUENCES WHERE CACHE_SIZE < 100;
重点关注 CACHE_SIZE < 100 且 ORDER_FLAG = 'Y' 的序列。如果看到 SYS.AUDSESS 或 SYS.AUDSED$ 也在结果里,说明登录风暴正在发生——这个系统序列默认 CACHE 20,短连接高并发时极易中招。
ALTER SEQUENCE 时最容易踩的坑
执行 ALTER SEQUENCE my_seq CACHE 1000 NOORDER 看似简单,但有三个实际影响必须清楚:
- 旧缓存立即失效,下次
NEXTVAL可能跳号(比如原缓存剩 3 个,新缓存从 1000 开始预占 1000 个) - 设太大(如
CACHE 50000)会导致实例崩溃时未用完的号段永久丢失,跳号幅度变大 - 如果业务真依赖“绝对连续”编号(比如财务凭证号),
NOCACHE也不能 100% 消除跳号——事务回滚了NEXTVAL,那个号就永远没了
JDBC 层不配合,Sequence 调再好也白搭
即使 Sequence 已开 CACHE 1000,Java 应用若在 for 循环里逐条执行 SELECT my_seq.NEXTVAL FROM DUAL,仍会因网络往返和 Statement 解析拖垮吞吐:
- 改用批量预取:
SELECT my_seq.NEXTVAL FROM DUAL CONNECT BY LEVEL <= 100,一次拿 100 个缓存在本地 List 复用 - 别用
PreparedStatement包裹NEXTVAL:Oracle 不支持参数化序列名,硬编码更高效 - Hibernate 默认
@GeneratedValue(strategy = GenerationType.SEQUENCE)每条 insert 都触发一次NEXTVAL查询;应显式配allocationSize = 50并确保 sequence 定义匹配
真正卡住的从来不是数据库本身,而是 Sequence 参数、RAC 模式、应用调用方式这三者没对齐。跳号可接受就放开 NOORDER,并发高就拉高 CACHE,但 JDBC 层不批量取值,再大的 CACHE 也只用上了第一个数。



















