DBMS_JOB不支持自动重试,失败后仅标记BROKEN=TRUE并设NEXT_DATE为4000-01-01,仅记录FAILURES计数且无错误详情;而DBMS_SCHEDULER需显式配置MAX_FAILURES、RESTART_ON_FAILURE等属性才能启用可控重试。
oracle 12c 中没有“物化视图刷新失败后自动重试”的独立开关,必须用 dbms_scheduler 显式配置重试行为;dbms_job 不支持重试,且错误日志缺失严重,生产环境应弃用。
为什么 DBMS_JOB 不能用于自动重试
DBMS_JOB 的失败处理是单次尝试 + 自动标记 BROKEN = TRUE,不提供重试次数、间隔或失败原因记录。一旦作业连续失败(默认仅重试 1 次),NEXT_DATE 就被设为 4000-01-01,作业彻底停摆。你查 DBA_JOBS 只能看到 FAILURES > 0,但无法知道是 ORA-02019 还是 ORA-12052——错误被静默吞掉。
- 执行
SELECT JOB, WHAT, BROKEN, FAILURES, NEXT_DATE FROM DBA_JOBS WHERE WHAT LIKE '%DBMS_MVIEW.REFRESH%',若BROKEN = 'TRUE'且NEXT_DATE = DATE '4000-01-01',说明已触发保护机制,不是配置问题,而是底层失败未解决 - 调用
DBMS_JOB.BROKEN(job => X, broken => FALSE, next_date => SYSDATE)只能临时恢复一次,下次失败仍会重复拉黑 -
DBMS_JOB作业日志只保留最近几次运行时间,不存错误堆栈,排查成本高
DBMS_SCHEDULER 创建时必须显式声明重试参数
Oracle 12c 默认使用 DBMS_SCHEDULER 管理物化视图刷新任务,但它不会自动启用重试——必须在创建作业时通过 SET_ATTRIBUTE 手动设置两个关键属性:
-
attribute => 'MAX_FAILURES', value => '3':允许最多连续失败 3 次,超过则作业状态变为DISABLED,不再尝试 -
attribute => 'RESTART_ON_FAILURE', value => 'TRUE':失败后按REPEAT_INTERVAL规则重试,不是立即重跑 - 务必同步设置
attribute => 'STOP_ON_WINDOW_CLOSE', value => 'FALSE',否则维护窗口关闭会导致作业终止且永不恢复
示例片段(创建 scheduler 作业):
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'REFRESH_MV_SALES',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN DBMS_MVIEW.REFRESH(''MV_SALES'', ''F''); END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0',
enabled => FALSE
);
DBMS_SCHEDULER.SET_ATTRIBUTE('REFRESH_MV_SALES', 'MAX_FAILURES', '3');
DBMS_SCHEDULER.SET_ATTRIBUTE('REFRESH_MV_SALES', 'RESTART_ON_FAILURE', 'TRUE');
DBMS_SCHEDULER.SET_ATTRIBUTE('REFRESH_MV_SALES', 'STOP_ON_WINDOW_CLOSE', 'FALSE');
DBMS_SCHEDULER.ENABLE('REFRESH_MV_SALES');
END;重试掩盖真实问题:必须前置验证 DBLINK 和日志状态
盲目开启重试,只会让错误延迟暴露。比如 DBLINK 断开时,DBMS_MVIEW.REFRESH 静默跳过,不更新 LAST_REFRESH_DATE,也不写入 DBA_MVIEW_REFRESH_LOGS,真实失败只记在 USER_SCHEDULER_JOB_LOG 中,且 STATUS = 'FAILED'(注意不是 'ERROR')。
- 查真实失败:运行
SELECT LOG_DATE, STATUS, ERROR#, ADDITIONAL_INFO FROM USER_SCHEDULER_JOB_LOG WHERE JOB_NAME = 'REFRESH_MV_SALES' AND STATUS = 'FAILED' ORDER BY LOG_DATE DESC - 验证 DBLINK:必须执行
SELECT * FROM DUAL@your_dblink,不能只查DBA_DB_LINKS——后者只存定义,不反映连通性 - 检查日志完整性:运行
SELECT LOG_TABLE, ROWIDS, SEQUENCE FROM USER_MVIEW_LOGS WHERE MASTER = 'SALES',若SEQUENCE = 'NO'或缺少关键列,FAST刷新必失败,FORCE会直接 fallback 到COMPLETE,锁表数小时
FORCE 刷新不等于智能重试,它只是 FAST → COMPLETE 的单次降级
FORCE 是物化视图的元数据属性,不是运行时策略。它永远先尝试 FAST,失败就立刻执行 COMPLETE,不重试、不等待、不判断日志积压量。如果日志损坏或缺失,FORCE 会静默走全量路径,而你可能几天后才发现性能陡降。
-
FORCE必须在建模时声明:CREATE MATERIALIZED VIEW mv_sales REFRESH FORCE ON DEMAND AS ...;运行时传参'F'不会覆盖已有策略 - 上线前建议用
DBMS_MVIEW.EXPLAIN_MVIEW验证FAST是否可行,避免依赖FORCE掩盖设计缺陷 - 真正需要“重试”的场景(如网络抖动),唯一可靠方式是在
job_action中包装 PL/SQL 块,先pingDBLINK,捕获ORA-02019或ORA-02068后 sleep + retry,而不是依赖 scheduler 自带重试
最易被忽略的一点:重试本身不修复日志堆积或 STALENESS = 'UNUSABLE'。这些状态会让后续所有 FAST 刷新持续失败,而重试只会不断触发 COMPLETE,最终导致 MLOG$_xxx 表膨胀、锁表加剧。必须把“查日志状态”和“修基表约束”当作重试前的强制步骤,而不是可选项。


















