oracle通过job定时执行任务

2013年8月27日 星期二 20:49

在项目中,经常会遇到需要定时完成的任务,比如定时更新数据,定义统计数据生成报表等等,其实这些事情都可以使用Oracle的Job来完成。下面考试大就结合我们实验室项目实际,简单介绍一下在Oracle数据库中通过Job完成自动创建表的方法。
  整个过程总共分为两步。虽然整个过程都非常简单,但是对于初学Oracle的生手还是有很多地方需要注意的。
  首先介绍一下,创建该JOB的背景,因为每天更新的直播和点播节目信息比较多,为了方便处理,需要每天创建一张表来记录更新的节目信息,当前数据库中已经有一张tbl_programme的表,每天创建的表的字段需要同tbl_programme保持一致,每天新创建的表的名称格式为tbl_programme_日期(例如:tbl_programme_20090214)规定每天晚上1点钟生成该天的新表。
  第一步:创建一个执行创建操作的存储过程
  在这一步首先要解决的问题就是构造表名。在Oracle中格式化输出时间可以用to_char函数来处理,例如:

  SQL> select to_char(sysdate, ’yyyy/mm/dd hh24:mi:ss’) from dual;
  TO_CHAR(SYSDATE,’YYYY/MM/DDHH2
  ------------------------------
  2009/02/14 17:22:41
  --以上SQL格式化输出了时间,要得到我们所需要的格式直接修改一下SQL即可
  SQL> select to_char(sysdate, ’yyyymmdd’) from dual;
  TO_CHAR(SYSDATE,’YYYYMMDD’)
  ---------------------------
  20090214
  得到时间格式字符串后我们就可以将表名的前缀和时间连接在一起形成完整的表名。这里需要注意,在Oracle中连接两个字符串需要使用‘||’符号,而在Sql Server中直接使用‘+’号就可以了,因为我以前一直在Sql Server下编程,好久都没编写Oracle的SQL所以费了很大的功夫才发现这个问题。完整的Sql就是
  SQL> select ’tbl_programme_’ || to_char(sysdate, ’yyyymmdd’) from dual;
  ’TBL_PROGRAMME_’||TO_CHAR(SYSD
  ------------------------------
  tbl_programme_20090214
  接下来就是创建表的代码了,因为新表需要tbl_programme保持一致,所以直接CTAS来创建表那是非常适合的了,代码如下:
  Create table tablename as select * from tbl_programme
  如果需要指定一个TableSpace则将该SQL做适当修改:
  Create table tablename tablespace p2p as select * from tbl_programme
  所以整个创建存储过程的SQL就是
  create or replace procedure sp_createtab_tbl_programme
  Authid Current_User
  as
  tabname varchar(200);
  begin
  select ’TBL_PROGRAMME_’ || to_char(sysdate, ’yyyymmdd’) into tabname fromdual;
  --create table tabname as select * from tbl_programme where 1 != 1;
  execute immediate ’create table ’ || tabname ||’ tablespace p2p as select* from tbl_programme where 1 != 1’;
  commit;
  end;
  /
  这里还需要注意一下在Oracle里面如果要对一个变量赋值的话有两种方式:
  (1)使用:=进行赋值
  (2)使用select ‘xjkxj ’ into 变量名称 from tabname
  另外,在存储过程中定义变量的时候一般放在as/is后begin前面。在存储过程一般是不能直接使用create table,truncate table这类似的语句的,如果要使用这些语句必须使用excute immediate + 所要执行的sql语句来实现。
  注意上面用红色标志的语句:Authid Current_User
  这个语句比较重要,如果我们在创建存储过程的时候不添加这条语句执行该存储过程将不会成功,原因是默认情况向存储过程是没有Create table等权限的,即使当前用户有DBA的权限也不行,如果存储过程中存在创建表的操作,可以有以下两种方式来解决该问题。
  (1)显示的赋予该用户Create table的权限,grant create table to user.
  (2)在存储过程中使用Authid Current_User 标识使用当前用户的权限。
  第二步:创建JOB
  创建JOB就比较简单了,下面就是创建JOB的代码
  每天晚上1电job启动一次,执行sp_createtab_tbl_programme存储过程。
  VARIABLE testjobid number;
  begin
  sys.dbms_job.submit(:testjobid,’sp_createtab_tbl_programme;’,trunc(sysdate+1)+1/24,’trunc(sysdate+1)+1/24’);
  commit;
  end;
  /
  这里需要注意的是,在submit方法的前面一定要先定义job这个变量,另外,submit方法的第二个参数是一个存储过程的名,记得在后面添加“:”号,在next_date是一个时间类型变量而不是一个字符串,所以需要注意不要把它当成字符串,不需要对该参数加引号。最后一个参数interval是一个字符串类型,记得添加引号。最常见的错误如下图所示:
  ORA-01008: not all variables bound就是没有定义变量的意思。一定记的在使用submit方法时定义jobid变量。
  下面是常有的设置Interval的方法:
  2 每天固定时间运行,比如早上8:10分钟:Trunc(Sysdate+1) + 8/24
  ² 每天:trunc(sysdate+1)
  ² 每周:trunc(sysdate+7)
  ² 每月:trunc(sysdate+30)
  ² 每个星期日:next_day(trunc(sysdate),’SUNDAY’)
  ² 每天6点:trunc(sysdate+1)+6/24
  ² 半个小时:sysdate+30/1440
  需要用到的完整SQL如下:
  
-----------------------------------------------------
  -- Export file for user P2P --
  -- Created by Administrator on 2009-2-14, 15:45:18 --
  -----------------------------------------------------
  spool gjgdp2p(v1.3).log
  promptprompt Creating procedure SP_CREATETAB_TBL_PROGRAMME
  prompt =============================================
  prompt
  create or replace procedure sp_createtab_tbl_programme
  Authid Current_User
  as
  tabname varchar(200);
  begin
  select ’TBL_PROGRAMME_’ || to_char(sysdate, ’yyyymmdd’) into tabname fromdual;
  --create table tabname as select * from tbl_programme where 1 != 1;
  execute immediate ’create table ’ || tabname ||’ tablespace p2p as select *from tbl_programme where 1 != 1’;
  commit;
  end;
  /
  VARIABLE testjobid number;
  begin
  sys.dbms_job.submit(:testjobid,’sp_createtab_tbl_programme;’,trunc(sysdate+1)+1/24,’trunc(sysdate+1)+1/24’);
  commit;
  end;
  /
  spool off

第三步:异常情况处理

JOB不能运行情况处理
  1.先来了解一下JOB的参数说明:与job相关的参数一个是job_queue_processes,这个是运行JOB时候所起的进程数,当然系统里面JOB大于这个数值后,就会有排队等候的,最小值是0,表示不运行JOB,最大值是36,在OS上对应的进程时SNPn,9i以后OS上管理JOB的进程叫CJQn.可以使用下面这个SQL确定目前有几个SNP/CJQ在运行。
  select * from v$bgprocess,这个paddr不为空的snp/cjq进程就是目前空闲的进程,有的表示正在工作的进程。
  另外一个是job_queue_interval,范围在1——3600之间,单位是秒,这个是唤醒JOB的process,因为每次snp运行完他就休息了,需要定期唤醒他,这个值不能太小,太小会影响数据库的性能。
  2.诊断:先确定上面这两个参数设置是否正确,特别是第一个参数,设置为0了,所有JOB就不会跑,确认无误后,我们继续向下。
  3.使用下面的SQL察看JOB的的broken,last_date和next_date,last_date是指最近一次job运行成功的结束时间,next_date是根据设置的频率计算的下次执行时间,根据这个信息就可以判断JOB上次是否正常,还可以判断下次的时间对不对,SQL如下:
  select * from dba_jobs
  有时候我们发现他的next_date是4000年1月1日,说明job要不就是在running,要不就是状态是break(broken=Y),如果发现JOB的broken值为Y,找用户了解一下,确定该JOB是否可以broken,如果不能broken,那就把broken值修改成N,修改再使用上面的SQL察看就发现他的last_date已经变了,JOB即可正常运行,修改broken状态的SQL如下:
  declare
  BEGIN
  DBMS_JOB.BROKEN(<JOB_ID>,FALSE);
  END;
  4.使用下面的SQL查询是否JOB还在Running
  select * from dba_jobs_running
  如果发现JOB已经Run了很久了还没有结束,就要查原因了。一般的JOB running时会锁定相关的相关的资源,可以查看一下v$access和v$locked_object这两个view,如果发现其他进程锁定了与JOB相关的Object,包括PKG/Function/Procedure/Table等资源,那么就要把其他进程删除,有必要的话,把JOB的进程也删除,再重新跑看看结果。
  5.如果上面都正常,但是JOB还不run,怎么办?那我们要考虑把JOB进程重启一次,防止是SNP进程死了造成JOB不跑,指令如下:
  alter system set job_queue_processes=0 ——关闭job进程,等待5——10秒钟
  alter system set job_quene_processes=5 ——恢复原来的值

 

上一篇:团队培训体系建设及执行


下一篇:[20120104]稳定一条sql语句的执行计划.txt