碰到一个有意思的情况,一个11gr2的数据库的JOB无法自动运行。
这是一个测试数据库。前一段时间运行了一个建立分区表的SQL语句,目的是测试最大分区数,因此设置的分区数是1048575。关于这个测试的详细信息可以参考:http://yangtingkun.itpub.net/post/468/499902
这个SQL运行时间超过了一个星期,由于是测试数据库,我也没有在意,本打算看看是否能最终跑完。没想到前两天测试机房断电,于是这个服务器就异常关闭了。
尝试启动数据库,并未发现异常,数据库的启动也不算太慢。不过当用户访问TAB同义词的时候,出现了长时间的等待,显然Oracle运用了快速恢复启动的技术,由于前面的CREATE TABLE已经建立了大量的分区信息,而这些信息由于没有最终提交因此都需要进行回滚。可以想象,这个运行时间超过1个星期的SQL,在回滚的时候显然也会需要很长的时间,Oracle为了避免数据库长时间无法打开,采用了延迟回滚的技术。数据库的日志一旦恢复完成,就可以打开使用,回滚并不会马上进行。如果用户触发到需要回滚的数据,则会发生等待,直到数据库处理完需要回滚的操作为止。
正是这种技术,使得Oracle可以快速的打开并使用,而后台会继续处理这些回滚的操作,除非用户访问到需要回滚的数据,否则不会意识到数据库的操作。
不过除了上面提到的访问TAB等视图被锁之外,还发现了一个奇怪的现象,数据库的JOB无法自动运行:
SQL> conn yangtk/yangtk
已连接。
SQL> create table t_id (id number);
表已创建。
SQL> select * from user_jobs;
未选定行
SQL> show parameter job
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes integer 100
SQL> declare
2 v_job number;
3 begin
4 dbms_job.submit(v_job, 'begin insert into t_id values (1); commit; end;', sysdate, 'sysdate + 1');
5 commit;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> select * from t_id;
未选定行
SQL> select job, this_date, next_date, total_time, broken, failures
2 from user_jobs;
JOB THIS_DATE NEXT_DATE TOTAL_TIME B FAILURES
---------- -------------- -------------- ---------- - ----------
63 20-5月 -10 0 N
可以看到,JOB并未自动运行,手工运行JOB则没有问题:
SQL> exec dbms_job.interval(63, 'sysdate + 1/1440');
PL/SQL 过程已成功完成。
SQL> commit;
提交完成。
SQL> exec dbms_job.run(63)
PL/SQL 过程已成功完成。
SQL> select * from t_id;
ID
----------
1
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
会话已更改。
SQL> select job, this_date, next_date, total_time, broken, failures
2 from user_jobs;
JOB THIS_DATE NEXT_DATE TOTAL_TIME B FAILURES
---------- ------------------- ------------------- ---------- - ----------
63 2010-05-20 02:18:13 0 N 0
SQL> select sysdate from dual;
SYSDATE
-------------------
2010-05-20 02:19:12
SQL> select * from t_id;
ID
----------
1
SQL> select job, this_date, next_date, total_time, broken, failures
2 from user_jobs;
JOB THIS_DATE NEXT_DATE TOTAL_TIME B FAILURES
---------- ------------------- ------------------- ---------- - ----------
63 2010-05-20 02:18:13 0 N 0
但是运行JOB后,这个JOB并没有继续自动运行,而是停了下来。检查操作系统发现cjq0进程存在,但是不存在J00N进程。检查alert文件,没有发现JOB相关的错误。
尝试通过设置JOB_QUEUE_PROCESSES为0,然后在设置一个非0值,来重新唤起JOB进程:
SQL> alter system set job_queue_processes = 0;
系统已更改。
SQL> alter system set job_queue_processes = 20;
系统已更改。
正常情况下,设置JOB_QUEUE_PROCESSES参数为0,会导致CJQ0进程推出,但是等待了很长时间发现CJQ0进程并未退出,只好重新设置JOB_QUEUE_PROCESSES为非零值。
通过DBMS_IJOB.ENABLE检查数据库的JOB是否正常:
SQL> CONN / AS SYSDBA
已连接。
SQL> SET SERVEROUT ON
SQL> BEGIN
2 IF DBMS_IJOB.ENABLED THEN
3 DBMS_OUTPUT.PUT_LINE('TRUE');
4 ELSE
5 DBMS_OUTPUT.PUT_LINE('FALSE');
6 END IF;
7 END;
8 /
TRUE
PL/SQL 过程已成功完成。
强制关闭JOB,然后在启用,问题依旧:
SQL> EXEC DBMS_IJOB.SET_ENABLED(FALSE)
PL/SQL 过程已成功完成。
SQL> EXEC DBMS_IJOB.SET_ENABLED(TRUE)
PL/SQL 过程已成功完成。
登陆目标用户,JOB仍然没有运行:
SQL> conn yangtk/yangtk
已连接。
SQL> select * from t_id;
ID
----------
1
SQL> select job, this_date, next_date, total_time, broken, failures
2 from user_jobs;
JOB THIS_DATE NEXT_DATE TOTAL_TIME B FAILURES
---------- ------------------- ------------------- ---------- - ----------
63 2010-05-20 02:18:13 0 N 0
由于时间比较晚,没有再继续追查下去。而随后一天比较忙,也没有来得及看
等到第三天准备继续检查这个问题的时候,发现JOB已经开始自动运行了:
SQL> select job, this_date, next_date, total_time, broken, failures
2 from user_jobs;
JOB THIS_DATE NEXT_DATE TOTAL_TIME B FAILURES
---------- ------------------- ------------------- ---------- - ----------
63 21-5月 -10 21-5月 -10 42 N 0
SQL> select * from t_id;
ID
----------
1
1
.
.
.
1
1
1
1
已选择2113行。
和JOB没有启动时唯一的区别在于,Oracle后台的回滚操作已经完成。
存在两种可能性,一种是Oracle在自动回滚的过程中禁止JOB的运行,避免冲突的发生;另一种可能是尝试启动JOB的时候,Oracle访问了数据字典,但是被自动回滚任务锁住。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-663399/ ,如需转载,请注明出处,否则将追究法律责任。