row cache lock等待高时,应查v$active_session_history按p1分组定位争用缓存类型,再关联v$rowcache确认具体字典项(如dc_sequences),结合p2/p3判断锁模式冲突,并通过sql_opname和program识别源头操作。
row cache lock 等待高,大概率是某个数据字典项被高频争用,ash 能直接定位到具体缓存类型和会话行为,比盲调参数更可靠。
查 v$active_session_history 定位争用缓存类型
ASH 中的 p1 字段就是 cache#,对应 v$rowcache.cache#。先快速锁定是哪个字典缓存被卡住:
- 执行:
SELECT p1, COUNT(*) FROM v$active_session_history WHERE event = 'row cache lock' AND sample_time > SYSDATE - 1/24 GROUP BY p1 ORDER BY 2 DESC; - 拿到最高频的
p1值(比如是8),再查名称:SELECT parameter FROM v$rowcache WHERE cache# = 8; - 常见值含义:
dc_sequences(序列)、dc_objects(对象定义)、dc_users(用户权限)、dc_tablespaces(表空间)
结合 p2/p3 判断锁模式冲突
p2 是当前持有锁的模式,p3 是等待者请求的模式。Oracle 内部用数字表示,关键对照如下:
-
KQRMX = 5:排他锁(X),通常来自 DDL、序列递增、权限变更等修改操作 -
KQRMS = 3:共享锁(S),通常来自查询类操作(如SELECT * FROM user_tables) - 若大量等待行中
p2 = 5且p3 = 3,说明一个会话长期持 X 锁(比如大事务中 ALTER TABLE),其他会话全在等 S 锁读取该字典项 - 若
p2 = 3且p3 = 5,则可能是多个会话试图同时改同一项(如并发 GRANT)
过滤会话行为,确认源头 SQL 或操作
不能只看锁,得知道谁在触发它。用 session_id 关联历史 SQL:
- 查最近执行过什么:
SELECT sql_id, sql_opname, program FROM v$active_session_history WHERE event = 'row cache lock' AND p1 = &p1_value AND sample_time > SYSDATE - 1/48 ORDER BY sample_time DESC FETCH FIRST 10 ROWS ONLY; - 重点看
sql_opname:如果是INSERT+ 序列NEXTVAL,指向dc_sequences;如果是PARSE或DDL,就往dc_objects或dc_users深挖 - 注意
program列:比如oracle@db01 (J000)可能是自动任务(统计信息收集),jdbc thin client就是应用层高频调用
区分 RAC 和单实例的等待特征
RAC 下 row cache lock 的等待逻辑和单实例不同,容易误判:
- RAC 中前台进程不直接申请锁,而是由
LCK0进程代为协调;等待超时默认是 60 秒,不是单实例的 3 秒 - 若在 RAC 环境发现大量
row cache lock且p1指向dc_sequences,90% 是没设CACHE的序列——每次NEXTVAL都要跨实例更新seq$表,引发全局行缓存同步开销 - 单实例下同问题也可能出现,但更常伴随共享池压力(比如硬解析暴涨导致
dc_objects频繁访问)
真正难处理的不是“看到等待”,而是“看不出哪个具体字典项在被争用”。ASH 的 p1 必须和 v$rowcache 对齐,否则所有优化动作都是蒙的。另外,别一上来就加 CACHE,先确认是不是某条 DDL 卡住了——那种情况加缓存毫无意义。











