根本原因是atomic_refresh=>FALSE下TRUNCATE触发字典缓存刷新,引发多会话争抢row cache latch;需通过V$ROWCACHE GETMISS激增和v$session event='row cache lock'联合诊断。

物化视图刷新触发的 ROW CACHE LOCK 争用,本质是字典缓存被 DDL 操作(如 TRUNCATE)强制刷新导致的短时高并发争抢,不是 SQL 写法问题,而是刷新模式与共享池状态耦合引发的连锁反应。
为什么 REFRESH 会引发 row cache lock?
Oracle 在 atomic_refresh => FALSE 模式下走 TRUNCATE + INSERT /*+ APPEND */ 路径,TRUNCATE 是 DDL,会触发数据字典变更,进而强制刷新 row cache(即 V$ROWCACHE 中的 dc_objects、dc_users 等条目)。此时若大量会话正密集解析新 SQL(依赖这些字典项),就会在 row cache latch 上排队等待,表现为 event = 'row cache lock',v$session.wait_class = 'Concurrency'。
常见现象包括:
- 多个会话
wait_event显示row cache lock,seconds_in_wait持续增长 -
V$ROWCACHE中GETS高但GETMISS突增,MODIFICATIONS显著上升 - ASH 样本中出现大量
blocking_session为空、但final_blocking_session指向 J000(作业进程)的记录
atomic_refresh => FALSE 后仍卡住,怎么确认是 row cache 问题?
不能只看锁表或行锁,要直查字典缓存层。执行以下诊断组合:
- 立刻查
V$ROWCACHE:重点关注PARAMETER = 'dc_objects'或'dc_users'的GETMISS/GETS比值是否 > 10%,且MODIFICATIONS在刷新窗口内激增 - 关联
V$SESSION:筛选event = 'row cache lock'且sql_id IS NULL(说明卡在解析前)的会话,检查其program是否为J000或ora_q001 - 对比刷新前后:运行
SELECT COUNT(*) FROM v$rowcache WHERE GETMISS > 1000,若刷新后该值翻倍,基本可锁定
如何降低 row cache lock 冲击?
核心思路是「错峰 + 缓冲 + 收敛」,而非禁用刷新:
- 避开业务高峰执行刷新,尤其避免在应用刚启动、SQL 大量硬解析时段触发
- 对频繁刷新的物化视图,预先执行
ALTER SESSION SET RESULT_CACHE_MODE = FORCE,减少后续查询对字典缓存的依赖 - 若使用 DBMS_MVIEW.REFRESH,显式传参
atomic_refresh => FALSE+parallelism => 2,避免单线程 DDL 长时间持 latch - 不推荐
ALTER SYSTEM FLUSH SHARED_POOL—— 这会主动制造更大规模的 row cache miss,雪上加霜
PostgreSQL 用户注意:这不是 Oracle 特有现象
PostgreSQL 的 REFRESH MATERIALIZED VIEW CONCURRENTLY 虽绕过 ACCESS EXCLUSIVE 锁,但重建唯一索引过程仍会短暂持有 RowExclusiveLock 并触发行缓存更新。若基表上有高频 INSERT/UPDATE,同样可能观察到 row cache lock 类似等待(对应 PG 的 pg_stat_activity.wait_event 为 BufferPin 或 RelationMapLock)。验证方式一致:查 pg_stat_bgwriter 中 buffers_checkpoint 是否突增,结合 pg_locks 看 locktype = 'object' 的等待分布。
row cache lock 的隐蔽性在于它不暴露具体对象名,也不出现在 SQL_ID 关联链中;真正麻烦的从来不是锁本身,而是你查不到谁在刷、为什么刷、以及刷完之后那几秒里,所有新连接都在默默排队等字典项重载。


















