物化视图刷新时cpu过高本质是执行计划失控:因统计信息陈旧、缺失物化视图日志或隐式参数bug导致全表扫描与哈希连接;应查v$session与v$sql_plan定位问题,禁用并行、收集基表统计信息、验证fast可行性并临时关闭查询重写。
物化视图刷新时 dbms_mview.refresh 占用 cpu 过高,本质是执行计划失控
oracle 12c 默认使用 dbms_mview.refresh 的 fast 或 complete 模式时,若底层查询含复杂连接、未建合适物化视图日志(mlog$)、或基表统计信息陈旧,优化器可能生成全表扫描+大量排序/哈希连接的执行计划,直接拖垮 cpu。这不是“刷新本身慢”,而是 sql 执行失控。
实操建议:
- 先查正在执行的刷新会话:
SELECT sid, serial#, sql_id, event FROM v$session WHERE program LIKE '%DBMS_MVIEW%',再用SELECT * FROM v$sql_plan WHERE sql_id = ''看实际执行计划,重点关注TABLE ACCESS FULL和HASH JOIN节点是否出现在大表上 - 强制禁用并行(尤其在 OLTP 环境):
EXEC DBMS_MVIEW.REFRESH('MV_NAME', method => 'C', parallelism => 0)—— 并行度 > 1 在小资源机器上反而因调度开销加剧 CPU 尖峰 - 刷新前手动收集基表统计信息:
DBMS_STATS.GATHER_TABLE_STATS(注意:不是只刷物化视图本身,而是它依赖的所有基表)
FAST 刷新失败退化为 COMPLETE 导致隐式全量重算
当物化视图定义含 ROWID、JOIN 或聚合,但对应基表缺失物化视图日志,或日志中缺少必要列(如 SNAPTIME$$ 字段被误删),Oracle 会在运行时静默降级为 COMPLETE 刷新——用户以为在增量更新,实际在扫全表。
检查方式与修复:
- 确认日志存在且有效:
SELECT master, log_table FROM user_mview_logs WHERE master IN ('T1','T2');若无结果,需补建:CREATE MATERIALIZED VIEW LOG ON t1 WITH ROWID, SEQUENCE(col1,col2) INCLUDING NEW VALUES - 验证 FAST 可用性:
EXEC DBMS_MVIEW.EXPLAIN_MVIEW('MV_NAME'),查EXPLAIN_MVIEW输出表,重点看msgtxt是否含"fast refreshable: NO"或"reason: missing materialized view log" - 刷新时显式指定模式并捕获错误:
DBMS_MVIEW.REFRESH('MV_NAME', 'F', atomic_refresh => FALSE),避免隐式降级;若报错ORA-12004(REFRESH FAST cannot be used),说明必须先修日志
物化视图查询重写(Query Rewrite)开启后反向加剧刷新压力
当 QUERY_REWRITE_ENABLED=TRUE 且有大量 SQL 依赖该物化视图做重写,刷新期间 Oracle 会尝试使相关游标失效、重新硬解析,引发 Library Cache Latch 争用,CPU 表现为 kksfbc 或 kgldlc 函数高占比。
临时缓解策略:
- 刷新前关闭重写:
ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE(会话级)或ALTER MATERIALIZED VIEW mv_name DISABLE QUERY REWRITE(对象级) - 避开业务高峰刷新,改用
ATOMIC_REFRESH => FALSE:先 truncate 再 insert,减少 DML 锁等待时间,间接降低 CPU 持续占用时长 - 监控重写触发频率:
SELECT * FROM v$mvrefresh查当前刷新队列;SELECT name, value FROM v$sysstat WHERE name LIKE '%query rewrite%'看重写调用基数
Oracle 12c 特定 Bug:_mv_refresh_use_stats 隐式参数引发计划抖动
12.1.0.2~12.1.0.7 中存在已知 Bug(Bug 20808905),当隐式参数 _mv_refresh_use_stats=TRUE(默认值)时,刷新内部生成的 SQL 会错误复用过期统计信息,导致执行计划反复劣化。现象是同一刷新任务,有时快有时慢,AWR 中 SQL ordered by CPU Time 排名剧烈波动。
绕过方案(需 DBA 权限):
- 临时修改会话级参数:
ALTER SESSION SET "_mv_refresh_use_stats" = FALSE,再执行刷新 - 升级至 12.2 或应用最新 RU(Release Update),该参数在 12.2+ 已废弃,逻辑重构为更稳定的统计信息绑定机制
- 不推荐全局修改该隐式参数,可能影响其他 MV 刷新行为;仅对确认受此 Bug 影响的物化视图做会话级覆盖
真正棘手的从来不是“怎么刷”,而是“刷的时候 Oracle 在后台悄悄干了什么”——尤其是 12c 中刷新逻辑与优化器深度耦合,一个没留意的统计信息、一行缺失的日志字段、甚至一个隐式参数,都可能让 CPU 使用率从 30% 跳到 95%。盯住 v$session + v$sql_plan,比盲目调并行数管用得多。











