Oracle程序,用于杀死在给定时间内未完成的作业

时间:2012-05-22 06:09:25

标签: oracle session plsql oracle11g jobs

我创建了一个oracle程序来重新安排在一定时间内没有完成的工作:

create or replace procedure kill_stuck_jobs
as
begin     
    for x in (  
            select j.sid,
                   s.spid,
                   s.serial#,
                   j.log_user,
                   j.job,
                   j.broken,
                   j.failures,
                   j.last_date,
                   j.this_date,
                   j.next_date,
                   j.next_date - j.last_date interval,
                   j.what
                  from 
                  (select 
                  djr.SID, 
                  dj.LOG_USER,
                  dj.JOB, 
                  dj.BROKEN,
                  dj.FAILURES, 
                  dj.LAST_DATE,
                  dj.LAST_SEC,
                  dj.THIS_DATE, dj.THIS_SEC, 
                  dj.NEXT_DATE, dj.NEXT_SEC, dj.INTERVAL, dj.WHAT
                  from dba_jobs dj, dba_jobs_running djr
                  where dj.job = djr.job ) j,
                  (select p.spid, s.sid, s.serial#
                  from v$process p, v$session s
                  where p.addr = s.paddr ) s
                  where j.sid = s.sid and 
                  j.next_date+15/1440 < sysdate  
        ) loop  
         EXEC DBMS_JOB.BROKEN(x.job,TRUE);
         execute immediate 'alter system disconnect session '''|| x.sid|| ',' || x.serial# || ''' immediate';
         EXEC DBMS_JOB.BROKEN(x.job,FALSE);
         dbms_output.put_line( 'Alter session done' );             
    end loop;  
end;  

但是这个程序会编译错误:

PLS-00103: Encountered the symbol "DBMS_JOB" when expecting one of the following:

   := . ( @ % ;
The symbol ":=" was substituted for "DBMS_JOB" to continue.

enter image description here

  • 以下讨论了dbms_job和dbms_scheduler_job。实际上这里的问题是我使用链接数据库创建了物化视图,但有时查询在与SQL*Net more data from dblink的会话中被卡住了一整天。我使用上面的过程来杀死在创建物化视图时创建的作业,我使用以下命令终止会话:

    create or replace procedure kill_stuck_refresh as 
     begin     
         for x in (  
                select username, osuser, sid, serial#, seconds_in_wait, 
                event, state, wait_class
                from v$session
                where username is not null 
                      and seconds_in_wait > 600 
                      and event = 'SQL*Net more data from dblink'  
            ) loop  
            execute immediate 'alter system disconnect session '''|| x.sid  
                         || ',' || x.serial# || ''' immediate';
            dbms_output.put_line( 'Alter session done' );             
         end loop;  
       end; -- end of kill_stuck_refresh; 
    

4 个答案:

答案 0 :(得分:4)

您的错误堆栈都源于您的游标无效。原因是ORA-00942。这可能意味着表名拼写错误,但是当您使用数据字典时,它通常指向权限问题,即您的范围中不存在表(或本例中的视图)。

这引起了我们的评论:

  

“我可以独立运行选择查询,我认为这意味着我有   那些特权。 “

这表明您的权限已授予您拥有权限的角色。我们可以使用通过SQL中的角色授予的权限,但不能使用它们来构建永久对象,例如视图或存储过程。为此,您需要对直接授予用户的视图拥有权限。没有解决方法,这是Oracle安全模型的工作方式。


顺便说一下,你应该调查为什么这些工作花了太长时间。我假设这是一个持久的问题(否则你为什么要建立一个存储过程来杀死这些工作?)。杀戮工作是一种生硬的工具,浪费资源并消除有用的证据。更好的想法是找出性能不佳的根本原因并加以修复。阻塞会话可能存在问题,您需要锁定策略。也许你已经很难调整SQL了。其他一些工作可能同时运行并吸收所有资源,在这种情况下,您需要一个体面的调度程序。或者你现在可能只有更多的数据 - 成功的代价 - 你需要给工作更多的时间来完成。

答案 1 :(得分:3)

在此上下文中(在存储过程/函数中)不需要EXEC。只有当您想从SQL(来自SQL * Plus)调用存储过程时才需要它。只需直接致电dbms_job.broken()

...
DBMS_JOB.BROKEN(x.job,TRUE);
execute immediate 'alter system disconnect session '''|| x.sid|| ',' || x.serial# || ''' immediate';
DBMS_JOB.BROKEN(x.job,FALSE);
dbms_output.put_line( 'Alter session done' );
...

答案 2 :(得分:2)

正如@David Aldridge所提到的,DBMS_Scheduler主要用于替换DBMS_Job(实际上以10g开头)。他没有提到的是为什么这会对你有所帮助。

DBMS_Scheduler提供了对其作业的更多控制,包括更好的日志记录。但是,对您来说最重要的是,DBMS_Scheduler会在作业中添加max_run_duration参数。如果作业的运行时间超过该持续时间,则作业将自动结束(并且可能以比杀死会话更优雅的方式)。然后,只要未设置max_failures参数,就会在下一个预定时间再次尝试作业。

如果您可以将当前作业迁移到DBMS_Scheduler,则可以省去编写代码以提供已存在的功能的麻烦。

答案 3 :(得分:1)

如果您使用的是Oracle 11g,那么您应该使用DBMS_Scheduler,而不是DBMS_Job。首先看一下迁移到新包,并在该环境中重新考虑您的需求。