我创建了一个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;
答案 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。首先看一下迁移到新包,并在该环境中重新考虑您的需求。