【问题标题】:Oracle procedure to kill jobs that do not complete in given time用于终止在给定时间内未完成的作业的 Oracle 过程
【发布时间】:2014-04-12 16:22:42
【问题描述】:

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

【问题讨论】:

    标签: oracle session plsql oracle11g jobs


    【解决方案1】:

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

    这让我们看到了你的评论:

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

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


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

    【讨论】:

    • 您能解释一下阻塞会话和锁定策略吗? SQL 进行了调整,因为它大部分时间只需要 7 秒,但由于它在早上和晚上的某个时间链接数据库,而远程系统很忙,它只是停留在会话中。
    • 甚至SYSTEM用户(安装oracle express时创建的用户)也无法编译这个程序。
    【解决方案2】:

    在这种情况下(在存储过程/函数中)您不需要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' );
    ...
    

    【讨论】:

    • 仍然没有正确编译我在sql developer中附加了错误文件。不知道是什么问题?
    • 您可以访问dba_*v$* 表吗?通常只有管理员帐户(SYSSYSTEM)可以访问这些。如果您无权访问,则需要授予您必要的权限(例如GRANT SELECT ON sys.v$_process TO &lt;username&gt;;)。在这些帐户下创建和运行任何代码是不明智的;最好将必要的权限(并且仅限于那些)授予有限权限的用户。
    • 您可能想使用ALTER SYSTEM KILL SESSION &lt;sid&gt;, &lt;serial#&gt;;。断开会话似乎相当残酷。杀死它会“回滚正在进行的事务,释放所有会话锁,并部分恢复会话资源”。
    • 我可以独立运行选择查询我认为这意味着我有这些特权。我将disconnet更改为kill..但仍然编译错误..
    • 我遇到了同样的错误,是关于v$session。实际上这与v$session 无关,因为如果我更改表格的顺序,那么它会抱怨v$process。我对一个非常相似的问题有一些模糊的回忆,但我不记得细节了。它与特权无关。如果我能记住问题(和解决方案)是什么,我会告诉你的。
    【解决方案3】:

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

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

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

    【讨论】:

    • 对像我这样的初学者来说很好的解释,但创造工作的是物化视图。
    【解决方案4】:

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

    【讨论】:

    • 这是明智的建议,但实际上并没有回答问题。
    • 确实如此,但它确实建议了提问者遵循的行动方案。
    猜你喜欢
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 2012-02-21
    • 2018-03-25
    • 1970-01-01
    相关资源
    最近更新 更多