背景:本人项目中有几个调度程序,其中有个job是每月月底最后一天晚上12点过执行,一开始运行的好好的 ,过了几个月业务需求调整,改为每月28号晚上12点过执行,于是我把job的运行时间由原来的TRUNC(ADD_MONTHS(SYSDATE,1),'MM')+1/1440
改为了TRUNC(SYSDATE,'MM')+28+5/1440,验证运行时间写的对不对
select to_char(TRUNC(SYSDATE,'MM')+28+5/1440,'yyyy-MM-dd hh24:mi:ss') from dual;
运行结果为
2019-05-29 00:05:00
看似没问题,然后我就编译 运行一次, job执行完,没有报错,确保存储过程脚本写的没问题,查看下次执行时间也正常,ok下班回家。。。。。
第二天来一看,数据没生成,再去看调度任务,NEXT_DATE时间不对,FAILURES错误次数长达13次, 吓得我赶紧先修改执行时间(必须必当前时间大),手动执行这个job。。。执行完再broken。
期间尝试改过很多运行时间的表达式,但每次到月底都是第一次手动编译运行没问题(排除存储过程语句写的是否问题),其次再等他自动运行 就不行了。网上看过很多解决方案,很多说是权限问题。。。 差点把我带跑偏,如果是权限问题 不可能其他job都能执行成功,于是问题还是出在表达式这。
在一个偶然的机遇下,请教了一位高人,他说这个表达式 貌似不能直接trunc sysdate ,必须要套一层函数 ,可以是last_day,亦或是add_month等。于是我再一次抱着尝试的心态去改改。
我改成了TRUNC(ADD_MONTHS(SYSDATE,0),'MM')+28+5/1440 (每月28号晚12点05分执行job...就是29日凌晨)
先验证下
select to_char(TRUNC(ADD_MONTHS(SYSDATE,0),'MM')+28+5/1440,'yyyy-MM-dd hh24:mi:ss') from dual;
--运行结果是2019-06-29 00:05:00
ok没问题 再编译运行一次,ok也没问题,坐等晚上自动执行,由于是今天才改的,只能等今晚过了才能得知结果,如果成功了 我再回来 更新下。
坐等。。
--------------------------------------------------------------------
我回来了 ---结果还是不行
我查看了日志
(我的目录是E:\app\Administrator\diag\rdbms\jwwlbj\jwwlbjtrace\alert_jwwlbj.log)
里面报错信息
到点执行 就提示已是过去时间
现在正在验证另一种解决方案................... 后面回来记录
回来了。。当前时间是19年7月29号上午, 这个月我把之前的job删掉了,重新建了一个job,把执行时间改成了TRUNC(ADD_MONTHS(SYSDATE,0),'MM')+27+1430/1440(28号晚上11点50执行)。
昨晚发生了这样的情况:job依旧执行失败,日志也同样的报ORA-12005,但是业务数据却生成了,意思就是job执行成功了又重复执行然后失败,这时我豁然开朗,先看下面一段话(查阅了深圳gg老师的一篇文章 手动@深圳gg)
官方解释:
Error code: ORA-12005
Description: may not schedule automatic refresh for times in the past
Cause: An attempt was made to schedule an automated materialized view refresh for a time in the past.
Action: Choose a time in the future instead.分析:INTERVAL的值+JOB开始运行的时间,算出下次执行时间在当前时间之前,所以报错ORA-12005: 不能安排过去时间的自动刷新。要想理解这个得知道JOB内部的工作。
JOB的工作流程:
1.JOB在运行结束之后才会更新next_date,但是计算的方法是JOB刚开始的时间加上interval设定的间隔。
2.如果在执行完JOB之后的时间比按照this_date+interval计算出的时间更晚一些,那么next_date就更新为当前时间,也就是几乎会立刻再重新执行JOB。
3.如果一个job执行failure后,oracle会尝试重新执行,若16次尝试后还是failure,则oracle会将这个job的broken设为true,即停掉这个job。
当job失败后,系统会在1分钟后重新运行这个JOB,如果还是失败,就在和第1次失败间隔2分钟的时候继续运行这个JOB,如果还是失败,就在和 第2次失败相隔4分钟后运行这个JOB,直到 失败间隔时间≥interval(JOB正常工作的时间设置参数)后,系统检测的时间间隔就为interval.直到第16次失败就会将这个job置为 broken。
由于执行时间是TRUNC(ADD_MONTHS(SYSDATE,0),'MM')+27+1430/1440。所以执行完一次后 ,执行时间判定还是当月,就又执行了一次, 就会出现ORA-12005导致执行失败,于是我最终这样改
执行时间改为:TRUNC(ADD_MONTHS(SYSDATE,1),'MM')+27+1430/1440。这下就没问题了,下个月来验证
--------------------------------------- 问题已解决 最终执行时间表达式TRUNC(ADD_MONTHS(SYSDATE,1),'MM')+27+1430/1440(每个月28号晚上11点50执行)