<p>enq: SQ - contention是序列争用的直接信号,常见于未启用CACHE的高并发NEXTVAL调用;需检查AWR中等待占比、Avg Wait及DBA_SEQUENCES中CACHE_SIZE=0/1或ORDER_FLAG='Y'等高风险配置。</p>

看Top 5 Timed Events里有没有enq: SQ - contention
这个等待事件就是序列争用的直接信号。它不会出现在单实例常规负载里,但一旦应用大量使用SEQUENCE.NEXTVAL且未启用缓存,就会高频出现。注意别和enq: TX - row lock contention混淆——后者是行锁,前者是序列号分配锁。
关键要看三列并读:Wait Time占比高(比如>10%)、Avg Wait低(通常Waits次数极高(每秒上千次)。这种“短而密”的等待模式,说明大量会话在排队抢同一个序列的下一个值。
- 如果
enq: SQ - contention排进Top 5,且Waits数值在快照期内超10万次,基本可锁定为瓶颈源 - RAC环境下要分实例看:用
@?/rdbms/admin/awrrpti.sql生成per-instance报告,避免节点间争用被平均掩盖 - 对比正常时段报告:若该事件在问题时段
Waits突增5倍以上,而业务QPS变化不大,大概率是序列定义或使用方式出了问题
查SQL ordered by Gets里是否含sequence.nextval或sys_op_lbid
AWR不会直接记录“谁在用序列”,但会把调用序列的SQL打上特征痕迹。重点关注SQL ordered by Gets列表中sql_text字段含以下内容的语句:
-
NEXTVAL或CURRVAL字面量(如INSERT INTO t VALUES (seq1.NEXTVAL, ...)) -
SYS_OP_LBID函数调用(Oracle内部用它访问序列缓存块,常出现在执行计划里) - 执行计划中出现
SEQUENCE操作符,且Buffer Gets per Exec异常高(>1000)
这类SQL往往逻辑简单、执行快,但Buffer Gets居高不下——因为每次取值都要访问序列的内存结构+回写缓存块,本质是争用而非计算。
确认序列定义是否缺失CACHE参数
这是最常见也最容易忽略的根因。没加CACHE的序列,每次NEXTVAL都触发一次全局锁+磁盘写(更新SEQ$表),在高并发下必然卡住。
查法很简单:在AWR报告的Instance Activity Stats节,找enqueue requests和enqueue releases差值;再结合DBA_SEQUENCES视图确认:
SELECT sequence_name, cache_size, order_flag FROM dba_sequences WHERE sequence_name = 'SEQ1';
-
CACHE_SIZE = 0或1→ 高风险,必须改 -
ORDER_FLAG = 'Y'→ 在RAC下进一步放大争用(强制跨节点同步序号) - 即使设了
CACHE 20,若单次批量插入只用1个值就commit,缓存实际利用率仍接近0
区分是序列本身争用还是应用层滥用
有时候enq: SQ - contention高,但不是序列定义问题,而是应用设计缺陷。比如:
- 循环内反复调用
seq.NEXTVAL生成主键,却不批量获取(应改用SELECT seq.NEXTVAL FROM DUAL CONNECT BY LEVEL ) - 用序列给非主键字段赋值(如日志流水号),且该字段无业务意义,纯属冗余调用
- PL/SQL过程里对同一序列连续调用多次
NEXTVAL,中间穿插DML,导致缓存块频繁刷写
这时AWR里会看到多个不同SQL共用同一个sql_id,但Executions per Sec极高、CPU per Exec极低——典型的“CPU没烧在计算,全耗在排队”。真要改,得动代码,不是DBA调参数能解决的。



















