首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 虚拟主机评测对比
Oracle作业(JOB)更新next_date的探讨-数据库专栏,ORACLE
作者:网友供稿 点击:17
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 

oracle作业(job)更新next_date的探讨

 

本文作者:kamus(kamus@itpub.net)

 

摘要:本文通过实验和事件跟踪来分析oracle job执行过程中修改下次执行时间的机制。

 

有些人问,oracle的job在设定完next_date和interval之后,到底是什么时候决定下一次运行时间的。可以归纳成以下几个问题。

1. 假设我们的job设定第一次运行的时间是12:00,运行的间隔是1小时,job运行需要耗时30分钟,那么第二次运行是在13:00还是13:30?

2. 如果是在13:00那是不是说明只要job一开始运行,next_date就被重新计算了?

3. job的下一次运行会受到上一次运行时间的影响吗?如果受到影响,如何可以避免这个影响而让job在每天的指定时刻运行?

 

本文通过一些实验和跟踪来解释上面的所有问题。

 

首先我们选择一个测试用户,假设该用户名为kamus。

由于我们在实验用的存储过程中会用到dbms_lock包,所以需要由sys用户先授予kamus用户使用dbms_lock包的权限。

 

d:\temp>sqlplus "/ as sysdba"

 

sql*plus: release 9.2.0.5.0 - production on 星期三 12月 1 23:56:32 2004

 

copyright (c) 1982, 2002, oracle corporation.  all rights reserved.

 

 

连接到:

oracle9i enterprise edition release 9.2.0.5.0 - production

with the partitioning, olap and oracle data mining options

jserver release 9.2.0.5.0 - production

 

sql> grant execute on dbms_lock to kamus;

 

授权成功。

 

然后用kamus用户登录数据库,创建我们测试使用的存储过程sp_test_next_date。

 

create or replace procedure sp_test_next_date as
  p_jobno    number;
  p_nextdate date;
begin
  --将调用此存储过程的job的next_date设置为30分钟以后
  select job into p_jobno from user_jobs where what = sp_test_next_date;;
  execute immediate begin dbms_job.next_date( || to_char(p_jobno) || ,sysdate+1/48);commit;end;;
  --修改完毕以后检查user_jobs视图,输出job目前的next_date
  select next_date
    into p_nextdate
    from user_jobs
   where what = sp_test_next_date;;
  dbms_output.put_line(job执行中的next_date: ||
                       to_char(p_nextdate,yyyy-mm-dd hh24:mi:ss));
  --等待10秒再退出执行
  dbms_lock.sleep(seconds => 10);
end sp_test_next_date;

 

创建调用该存储过程的job,定义interval为每天一次,也就是这次执行以后,下次执行时间应该在1天以后。

 

sql> variable jobno number;

sql> begin

  2  dbms_job.submit(job => :jobno,

  3  what => sp_test_next_date;,

  4  next_date => sysdate,

  5  interval => sysdate+1);

  6  commit;

  7  end;

  8  /

 

pl/sql 过程已成功完成。

 

jobno

---------

1

 

然后我们手工执行存储过程,执行完毕以后再手工从user_jobs视图中获得job的下次执行时间,可以看到在存储过程中修改的job的下次执行时间已经生效,变成了当前时间的30分钟以后,而不是默认的1天以后。

 

sql> conn kamus

请输入口令:

已连接。

sql> set serverout on

sql> exec sp_test_next_date();

job执行中的next_date: 2004-12-02 00:44:11

 

pl/sql 过程已成功完成。

 

sql> col next_date for a20

sql> select to_char(next_date,yyyy-mm-dd hh24:mi:ss) next_date from user_jobs

where what = sp_test_next_date;;

 

next_date

--------------------

2004-12-02 00:44:11

 

我们再手工运行job,看看这次的结果,可以发现job没有运行完毕以前被修改了的下次运行时间跟job运行完毕以后再次手工检索user_jobs视图获得的下次运行时间已经不相同了。由此我们可以得出一个结论,next_date是在job运行完毕以后被oracle自动修改的,而不是在job刚开始运行的时候,因为我们在存储过程中修改的next_date在job运行结束之后又被修改为默认的1天以后了。

 

sql> exec dbms_job.run(1);

job执行中的next_date: 2004-12-02 00:54:52

 

pl/sql 过程已成功完成。

 

sql> select to_char(next_date,yyyy-mm-dd hh24:mi:ss) next_date from user_jobs

where what = sp_test_next_date;;

 

next_date

--------------------

2004-12-03 00:24:52

 

现在我们再次修改存储过程,输出存储过程开始执行的时间,便于跟执行完毕以后的job下次执行时间进行比较。

 

create or replace procedure sp_test_next_date as
  p_jobno    number;
  p_nextdate date;
begin
  --输出job刚开始执行的时间
  dbms_output.put_line( job开始执行的时间: ||
                       to_char(sysdate, yyyy-mm-dd hh24:mi:ss));
  --将调用此存储过程的job的next_date设置为30分钟以后
  select job into p_jobno from user_jobs where what = sp_test_next_date;;
  execute immediate begin dbms_job.next_date( || to_char(p_jobno) || ,sysdate+1/48);commit;end;;
  --修改完毕以后检查user_jobs视图,输出job目前的next_date
  select next_date
    into p_nextdate
    from user_jobs
   where what = sp_test_next_date;;
  dbms_output.put_line( job执行中的next_date: ||
                       to_char(p_nextdate,yyyy-mm-dd hh24:mi:ss));
  --等待10秒再退出执行
  dbms_lock.sleep(seconds => 10);
end sp_test_next_date;

 

重新进行测试,我们可以发现job的next_date是job开始执行时间的1天以后,而不是job结束时间的1天以后(因为job结束需要经过10秒钟)

 

sql> exec dbms_job.run(1);

job开始执行的时间: 2004-12-02 00:38:24

job执行中的next_date: 2004-12-02 01:08:24

 

pl/sql 过程已成功完成。

 

sql> select to_char(next_date,yyyy-mm-dd hh24:mi:ss) next_date from user_jobs

where what = sp_test_next_date;;

 

next_date

--------------------

2004-12-03 00:38:24

 

至此,我们已经说明了两个问题。就是:job在运行结束之后才会更新next_date,但是计算的方法是job刚开始的时间加上interval设定的间隔。

 

下面我们通过trace来再次求证这个结论。

sql> alter session set events 10046 trace name context forever, level 12;

 

会话已更改。

 

sql> exec dbms_job.run(1);

 

pl/sql 过程已成功完成。

 

sql> alter session set events 10046 trace name context off;

 

会话已更改。

 

执行完毕以后在udump目录中查看生成的trace文件。如果我们用tkprof来格式化这个trace文件然后再查看格式化后的结果,我们会感到很诧异。因为在格式化完毕的sql执行顺序中,更新job$表的语句出现在dbms_job.next_date语句之前,也就是看上去是oracle先按照interval自动更新了job的next_date,然后才继续往下执行存储过程中定义的next_date更新语句,而这样显然无法解释我们在上面的实验中看到的结果。

但是当我们跳过tkprof而直接去查看生成的trace文件,就会恍然大悟,同时也印证了steve adams在ixora上提到的观点:tkprof格式化完的结果会省略一些信息,甚至在有时候会给我们错误的信息。

直接查看trace文件,我们可以看到如下的执行顺序:

1. parse cursor #10(oracle根据interval和先前保存的this_date字段值更新job$表的语句,包括更新failures, last_date, next_date, total等)

2. parse cursor #15(存储过程中的begin dbms_job.next_date语句)

3. binds cursor #15(将加上了30分钟的时间绑定到cursor #15上)

4. exec cursor #15(执行cursor #15)

5. wait cursor #11(经历一个pl/sql lock timer事件,也就是存储过程中执行的dbms_lock.sleep方法)

6. binds cursor #10(将job刚开始执行时候的时间绑定到cursor #10上)

7. exec cursor #10(执行cursor #10)

 

也就是说虽然更新job$的语句被很早地解析过了,但是直到job运行结束时这个被解析过的游标才开始作变量绑定进而开始执行。

正是因为解析update sys.job$语句的时间早于解析begin dbms_job.next_date语句的时间,所以tkprof的结果将前者放在了前面。

由于trace文件过长,所以不在本文中贴出了,如果有兴趣可以发邮件给我。我的邮件地址是:kamus@itpub.net

 

本文的最后一部分,解答本文开头提出的第三个问题,也就是:

job的下一次运行会受到上一次运行时间的影响吗?如果受到影响,如何可以避免这个影响而让job在每天的指定时刻运行?

job的下一次运行时间是会受上一次影响的,如果我们的interval仅仅是sysdate+1/24这样的形式的话,无疑,上次执行的时间再加上1小时就是下次执行的时间。那么如果job因为某些原因延迟执行了一次,这样就会导致下一次的执行时间也同样顺延了,这通常不是我们希望出现的现象。

解决方法很简单,只需要设定正确的interval就可以了。

比如,我们要job在每天的凌晨3:30执行而不管上次执行到底是几点,只需要设置interval为trunc(sysdate)+3.5/24+1即可。完整的sql如下:

sql> variable jobno number;

sql> begin

  2  dbms_job.submit(job => :jobno,

  3  what => sp_test_next_date;,

  4  next_date => sysdate,

  5  interval => trunc(sysdate)+3.5/24+1);

  6  commit;

  7  end;

  8  /

 

btw:在trace文件中发现虽然通过select rowid from table返回的结果已经是扩展rowid格式(data object number + file + block + row)了,但是oracle内部检索数据仍然在使用限制rowid格式(block number.row number.file number)。

 

本文涉及到的额外知识可以参看我的其它技术文章:

1. 通过事件跟踪sql执行的后台步骤

2. oracle等待事件,比如本文提到的pl/sql lock timer

3. rowid格式

 

作者简介:

张乐奕,网名kamus

曾任itpub oracle认证版版主,现任itpub oracle管理版版主.  

现任职于北京某大型软件公司,首席dba,主要负责证券行业的全国十数处核心交易系统数据库管理及维护工作。

热切关注oracle技术和其它相关技术,出没于各大数据库技术论坛,目前是中国最大的oracle技术论坛www.itpub.net的数据库管理版版主,

阅读更多技术文章和随笔可以登录我的个人blog。
http://blog.cdsn.net/kamus。

 

文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·Asp.Net下导出/导入规则的Excel(.xls)文件-ASP教程,ASP应用
·中国万网,万网
·中资源
·上海火速
·加拿大中文网
·华夏名网
·世纪东方
·商务中国
·中国E动网
·神话网络
最新文章
·photoshop抠图合成特效:飞出照片相框_photoshop教程
·将升级的windows vista驱动还原到原来的版本_windows vista
·photoshop漫画笔刷绘制非主流照片漫画_photoshop教程
·看域名注册信息判断网赚公司真假_网赚技巧
·找坐标:对网站进行坐标定位_站长心得
·如何增加网站pv_站长心得
·google性格一:对活跃度高的网页收录很快_google推广
·googleadsense容易被k的可能性列表_google推广
·价值数万的googlepr作弊方_google推广
·如何抢占人家的“首要意念”_google推广
相关主题
  • oracle rac 10.2 的在 linux 上的存储选项_数据库技巧
  • oracle sql精妙sql语句讲解_数据库技巧
  • oracle 10g 安装中一些问题解决_数据库技巧
  • oracle 10g + sql server 2000 透明网关设置_数据库技巧
  • oracle 存储过程的基本语法_数据库技巧
  • 西部数码虚拟主机

    友情链接
    CNNIC 西部数码
    万网 自助建站
    虚拟主机 asp空间
    域名注册 域名
    域名申请 主页空间
    论坛空间 网站空间
    国际域名 虚拟空间
    空间租用 DDOS防火墙
    成都主机托管 四川主机托管
    主机租用 服务器租用
    网站目录 自助建站
    虚拟主机 网址大全
    软件下载
    自助链接
    虚拟主机资讯 特价虚拟主机
    版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
    关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
    发表评论 打印  刷新     关闭