【Oracle】DBMS_JOB完全ガイド|ジョブの作成・変更・停止・DBMS_SCHEDULER との違いまで解説

Oracle には 2 種類のジョブスケジューラが存在します。DBMS_JOB(Oracle 7 以降の旧スケジューラ)とDBMS_SCHEDULER(Oracle 10g 以降の新スケジューラ)です。

DBMS_JOB は機能が限定的なためオラクル社は DBMS_SCHEDULER への移行を推奨しています。しかし既存のレガシーシステムでは DBMS_JOB が今も多く使われており、運用・保守のために理解が必要です。

この記事でわかること

  • DBMS_JOB の仕組みと DBMS_SCHEDULER との違い
  • DBMS_JOB.SUBMIT でジョブを登録する方法
  • interval パラメータの設定(毎日・毎時・特定曜日など)
  • DBMS_JOB.CHANGE / NEXT_DATE / INTERVAL でジョブを変更する方法
  • DBMS_JOB.BROKEN でジョブを無効化する方法
  • USER_JOBS / DBA_JOBS でジョブを管理・確認する方法
  • DBMS_SCHEDULER への移行方法
スポンサーリンク

DBMS_JOB と DBMS_SCHEDULER の比較

項目 DBMS_JOB DBMS_SCHEDULER
導入バージョン Oracle 7 以降 Oracle 10g 以降
スケジュール PL/SQL 式(interval パラメータ) カレンダー文字列・スケジュールオブジェクト
実行ログ USER_JOBS.FAILURES / WHAT USER_SCHEDULER_JOB_LOG(詳細なログ)
実行ユーザー ジョブ作成者のスキーマ ジョブ名・所有者を分離できる
外部プログラム PL/SQL のみ PL/SQL・外部実行ファイル・DB スクリプト
依存関係 なし チェーンで依存関係を定義可能
推奨度 非推奨(レガシー) 推奨(現在のスタンダード)

DBMS_JOB.SUBMIT でジョブを登録する

DBMS_JOB.SUBMIT の基本的な使い方
DECLARE
    v_job NUMBER;
BEGIN
    DBMS_JOB.SUBMIT(
        job      => v_job,              -- 出力: 割り当てられたジョブ番号
        what     => 'process_monthly_sales;',  -- 実行する PL/SQL 文(セミコロン必須)
        next_date => SYSDATE,           -- 最初の実行日時(即時実行は SYSDATE)
        interval => 'SYSDATE + 1/24',  -- 実行間隔(次の実行日時を計算する PL/SQL 式)
        no_parse => FALSE               -- FALSE: 登録時に what の構文チェックを行う
    );

    COMMIT;   -- DBMS_JOB.SUBMIT は COMMIT して初めて登録が確定する

    DBMS_OUTPUT.PUT_LINE('ジョブ番号: ' || v_job);
END;
/
interval パラメータのよく使うパターン
-- interval パラメータは「次回の実行日時を返す PL/SQL 式」を文字列で指定する
-- 式の中では SYSDATE が「前回の実行完了時刻」を表す

-- 毎日同じ時刻に実行(毎日午前 2 時)
interval => 'TRUNC(SYSDATE + 1) + 2/24'

-- 毎時 0 分に実行(1 時間ごと)
interval => 'TRUNC(SYSDATE, ''HH24'') + 1/24'

-- 毎週月曜日の午前 1 時に実行
interval => 'NEXT_DAY(TRUNC(SYSDATE), ''MONDAY'') + 1/24'

-- 毎月 1 日の午前 0 時に実行
interval => 'ADD_MONTHS(TRUNC(SYSDATE, ''MM''), 1)'

-- 10 分ごとに実行
interval => 'SYSDATE + 10/1440'

-- 1 回だけ実行(interval を NULL にするとジョブは自動削除される)
interval => NULL

-- 実行しない(BROKEN=TRUE)にする場合は interval を設定したまま BROKEN にする

ジョブを変更・停止する

DBMS_JOB.CHANGE / BROKEN / NEXT_DATE / INTERVAL
-- ジョブの設定をまとめて変更する(NULL は変更しない)
BEGIN
    DBMS_JOB.CHANGE(
        job      => 42,                          -- ジョブ番号
        what     => 'process_weekly_report;',   -- 新しい実行内容(NULL で変更しない)
        next_date => SYSDATE + 1,                -- 次の実行日時
        interval  => 'SYSDATE + 7'              -- 新しい間隔(1 週間)
    );
    COMMIT;
END;
/

-- 次の実行日時だけ変更する
BEGIN
    DBMS_JOB.NEXT_DATE(
        job       => 42,
        next_date => TRUNC(SYSDATE + 1) + 3/24  -- 翌日 3 時
    );
    COMMIT;
END;
/

-- 実行間隔だけ変更する
BEGIN
    DBMS_JOB.INTERVAL(
        job      => 42,
        interval => 'SYSDATE + 1/24'   -- 毎時間に変更
    );
    COMMIT;
END;
/

-- ジョブを一時停止する(BROKEN=TRUE でジョブが実行されなくなる)
BEGIN
    DBMS_JOB.BROKEN(
        job    => 42,
        broken => TRUE,              -- TRUE: 停止 / FALSE: 再開
        next_date => SYSDATE + 1    -- 再開時の次の実行日時
    );
    COMMIT;
END;
/

-- ジョブを手動で即時実行する
BEGIN
    DBMS_JOB.RUN(42);
END;
/

-- ジョブを削除する
BEGIN
    DBMS_JOB.REMOVE(42);
    COMMIT;
END;
/

USER_JOBS / DBA_JOBS でジョブを管理する

USER_JOBS でジョブを確認する
-- 自分のジョブを確認する
SELECT
    job,
    what,                                  -- 実行する PL/SQL 文
    next_date,                             -- 次回実行予定日時
    TO_CHAR(next_date, 'YYYY-MM-DD HH24:MI:SS') AS next_run,
    interval,                              -- 実行間隔式
    broken,                                -- Y: 停止中, N: 有効
    failures,                              -- 連続失敗回数(16 回でBROKEN=Yに自動変更)
    last_date,                             -- 最終実行日時
    last_sec,                              -- 最終実行時刻
    total_time                             -- 合計実行時間(秒)
FROM USER_JOBS
ORDER BY job;

-- DBA_JOBS(DBA 権限が必要): 全ユーザーのジョブを確認する
SELECT
    job, log_user, priv_user, schema_user,
    what, next_date, interval, broken, failures
FROM DBA_JOBS
ORDER BY log_user, job;

-- 現在実行中のジョブを確認する(DBA 権限が必要)
SELECT
    j.job,
    j.log_user,
    j.what,
    s.sid,
    s.serial#,
    s.username
FROM DBA_JOBS_RUNNING j
JOIN V$SESSION s ON j.sid = s.sid;

DBMS_SCHEDULER への移行方法

DBMS_JOB から DBMS_SCHEDULER へ移行する
-- DBMS_JOB のジョブ(毎日午前 2 時実行)を DBMS_SCHEDULER に移行する例

-- 移行前(DBMS_JOB)
-- DBMS_JOB.SUBMIT(v_job, 'process_monthly_sales;',
--     SYSDATE, 'TRUNC(SYSDATE + 1) + 2/24');

-- 移行後(DBMS_SCHEDULER)
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'MONTHLY_SALES_JOB',
        job_type        => 'STORED_PROCEDURE',
        job_action      => 'PROCESS_MONTHLY_SALES',
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0',
        enabled         => TRUE,
        comments        => '月次売上集計(DBMS_JOBからの移行)'
    );
END;
/

-- DBMS_SCHEDULER のジョブ実行ログを確認する(詳細なログが取れる)
SELECT
    job_name,
    status,
    run_duration,
    actual_start_date,
    error#,
    additional_info
FROM USER_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name = 'MONTHLY_SALES_JOB'
ORDER BY actual_start_date DESC
FETCH FIRST 10 ROWS ONLY;

まとめ

  • DBMS_JOB.SUBMIT:what(実行内容)・next_date(初回実行)・interval(次回実行を返すPL/SQL式)を指定してジョブを登録する。COMMIT が必要
  • interval の NULL:NULL にすると 1 回だけ実行して自動削除される
  • BROKEN:TRUE にするとジョブが実行されなくなる。16 回連続失敗でも自動的に BROKEN=Y になる
  • USER_JOBS.failures:連続失敗回数。0 に戻すには DBMS_JOB.BROKEN(job, FALSE) で再有効化する
  • 新規開発は DBMS_SCHEDULER を使う:詳細ログ・外部プログラム実行・チェーンなど機能が充実している

DBMS_SCHEDULER の詳細については DBMS_SCHEDULER完全ガイドを参照してください。PRAGMA AUTONOMOUS_TRANSACTION を使ったジョブのエラーログ記録は PRAGMA AUTONOMOUS_TRANSACTION完全ガイドも参照してください。