0

我创建了一个 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.

在此处输入图像描述

  • 这里是关于 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

4 回答 4

4

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

这给我们带来了您的评论:

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

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


顺便说一句,您应该调查为什么这些工作需要太长时间。我假设这是一个持续存在的问题(否则你为什么要构建一个存储过程来杀死这些工作?)。杀死工作是一种钝器,它浪费资源并抹杀有用的证据。一个更好的主意是找出性能不佳的根本原因并修复它。也许阻塞会话存在问题,您需要锁定策略。也许你的 SQL 调得不好。其他一些工作可能同时运行并占用所有资源,在这种情况下,您需要一个体面的调度程序。或者您现在可能刚刚获得了更多数据——成功的代价——并且您需要给工作更多的时间来完成。

于 2012-05-22T10:49:13.600 回答
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' );
...
于 2012-05-22T06:11:28.940 回答
2

正如@David Aldridge 提到的,DBMS_Scheduler 主要是为了取代 DBMS_Job(实际上是从 10g 开始)。他没有提到的是为什么这会对你有所帮助。

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

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

于 2012-05-22T14:52:34.800 回答
1

如果您使用的是 Oracle 11g,那么您应该使用 DBMS_Scheduler,而不是 DBMS_Job。首先看看迁移到新包,然后在这种情况下重新考虑您的要求。

于 2012-05-22T09:33:52.087 回答