【Oracle】DBMS_SCHEDULER完全ガイド|ジョブ作成・スケジュール管理・実行履歴確認・エラー対処まで解説

【Oracle】DBMS_SCHEDULER完全ガイド|ジョブ作成・スケジュール管理・実行履歴確認・エラー対処まで解説 Oracle

Oracle には2種類のジョブスケジューリング機能があります。旧来の DBMS_JOB(Oracle 8 以前から)と、Oracle 10g から導入された DBMS_SCHEDULER です。DBMS_SCHEDULER は柔軟なスケジュール指定・エラー時の動作制御・実行ログの管理など機能が豊富で、現在では DBMS_SCHEDULER の使用が推奨されています。

この記事でわかること

  • DBMS_SCHEDULER.CREATE_JOB でジョブを作成する方法
  • REPEAT_INTERVAL でのスケジュール指定(毎日・毎時・曜日指定など)
  • プログラム(CREATE_PROGRAM)とスケジュール(CREATE_SCHEDULE)を分離した設計
  • ジョブの有効化・無効化・手動実行・削除
  • DBA_SCHEDULER_JOBS・DBA_SCHEDULER_JOB_RUN_DETAILS でのジョブ監視
  • 実行エラーの確認と対処法
スポンサーリンク

基本的なジョブの作成(CREATE_JOB)

最もシンプルなジョブは DBMS_SCHEDULER.CREATE_JOB で作成します。job_type に PL/SQL ブロック・ストアドプロシージャ・外部スクリプトなどを指定できます。

毎日深夜2時に実行するジョブを作成する
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'DAILY_CLEANUP_JOB',         -- ジョブ名(スキーマ内でユニーク)
        job_type        => 'PLSQL_BLOCK',               -- PL/SQL ブロックを直接指定
        job_action      => '
            BEGIN
                -- 不要データの削除処理
                DELETE FROM log_table
                WHERE created_at < SYSDATE - 90;
                COMMIT;
            END;
        ',
        start_date      => SYSTIMESTAMP,                -- 即時開始(最初の実行は次のスケジュール時刻から)
        repeat_interval => 'FREQ=DAILY;BYHOUR=2;BYMINUTE=0;BYSECOND=0',
                                                        -- 毎日 2:00 に実行
        end_date        => NULL,                        -- 終了日なし(永続)
        enabled         => TRUE,                        -- 作成と同時に有効化
        auto_drop       => FALSE,                       -- 実行後にジョブを自動削除しない
        comments        => '90日以上前のログデータを毎日削除するジョブ'
    );
END;
/
ストアドプロシージャを呼び出すジョブ
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'MONTHLY_REPORT_JOB',
        job_type        => 'STORED_PROCEDURE',          -- ストアドプロシージャを呼び出す
        job_action      => 'PKG_REPORT.GENERATE_MONTHLY',  -- スキーマ.プロシージャ名
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=MONTHLY;BYMONTHDAY=1;BYHOUR=6;BYMINUTE=0;BYSECOND=0',
                                                        -- 毎月1日 6:00 に実行
        enabled         => TRUE,
        auto_drop       => FALSE,
        comments        => '月次レポートを毎月1日に生成するジョブ'
    );
END;
/

REPEAT_INTERVAL の書き方

REPEAT_INTERVALカレンダー式(iCalendar 構文ベース)で指定します。FREQ で繰り返し単位を指定し、BY* でさらに絞り込みます。

スケジュール REPEAT_INTERVAL の例
毎日 0:00 FREQ=DAILY;BYHOUR=0;BYMINUTE=0;BYSECOND=0
毎時 30 分 FREQ=HOURLY;BYMINUTE=30;BYSECOND=0
5分ごと FREQ=MINUTELY;INTERVAL=5
平日(月〜金)17:00 FREQ=DAILY;BYDAY=MON,TUE,WED,THU,FRI;BYHOUR=17;BYMINUTE=0;BYSECOND=0
毎月最終日 23:59 FREQ=MONTHLY;BYMONTHDAY=-1;BYHOUR=23;BYMINUTE=59;BYSECOND=0
毎週月曜 8:00 FREQ=WEEKLY;BYDAY=MON;BYHOUR=8;BYMINUTE=0;BYSECOND=0
毎年4月1日 9:00 FREQ=YEARLY;BYMONTH=APR;BYMONTHDAY=1;BYHOUR=9;BYMINUTE=0;BYSECOND=0
次回実行予定時刻を事前に確認する
-- REPEAT_INTERVAL の検証: 次の実行予定を3件確認する
SELECT NEXT_RUN_DATE
FROM (
    SELECT
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(
            'FREQ=WEEKLY;BYDAY=MON;BYHOUR=8;BYMINUTE=0;BYSECOND=0',
            SYSTIMESTAMP,
            SYSTIMESTAMP,
            SYSTIMESTAMP + INTERVAL '90' DAY
        ) AS NEXT_RUN_DATE
    FROM DUAL
    CONNECT BY LEVEL <= 3
);
-- ※ EVALUATE_CALENDAR_STRING は直接的な関数ではなく、以下の方法で代用する
次回実行時刻を確認する(正式な方法)
-- DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING で次の実行予定を確認
DECLARE
    v_next TIMESTAMP WITH TIME ZONE;
    v_current TIMESTAMP WITH TIME ZONE := SYSTIMESTAMP;
BEGIN
    FOR i IN 1 .. 5 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(
            calendar_string => 'FREQ=DAILY;BYDAY=MON,TUE,WED,THU,FRI;BYHOUR=9;BYMINUTE=0;BYSECOND=0',
            start_date      => SYSTIMESTAMP,
            return_date_after => v_current,
            next_run_date   => v_next
        );
        DBMS_OUTPUT.PUT_LINE('次回 ' || i || ': ' || TO_CHAR(v_next, 'YYYY-MM-DD HH24:MI:SS'));
        v_current := v_next;
    END LOOP;
END;
/

プログラムとスケジュールを分離した設計

同じプロシージャを複数のスケジュールで実行したい場合や、スケジュールを複数ジョブで共有したい場合は、プログラム(CREATE_PROGRAM)スケジュール(CREATE_SCHEDULE)を分離して作成します。

プログラムとスケジュールを分離して作成する
-- ① プログラムを作成(何を実行するか)
BEGIN
    DBMS_SCHEDULER.CREATE_PROGRAM(
        program_name    => 'PRG_ARCHIVE_DATA',
        program_type    => 'STORED_PROCEDURE',
        program_action  => 'PKG_ARCHIVE.RUN',
        enabled         => TRUE,
        comments        => 'データアーカイブ処理'
    );
END;
/

-- ② スケジュールを作成(いつ実行するか)
BEGIN
    DBMS_SCHEDULER.CREATE_SCHEDULE(
        schedule_name   => 'SCH_NIGHTLY_2AM',
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=DAILY;BYHOUR=2;BYMINUTE=0;BYSECOND=0',
        comments        => '毎日深夜2時'
    );
END;
/

-- ③ ジョブでプログラムとスケジュールを組み合わせる
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name      => 'JOB_ARCHIVE_NIGHTLY',
        program_name  => 'PRG_ARCHIVE_DATA',   -- ①で作成したプログラム
        schedule_name => 'SCH_NIGHTLY_2AM',    -- ②で作成したスケジュール
        enabled       => TRUE,
        comments      => '毎日深夜にアーカイブを実行'
    );
END;
/

ジョブの有効化・停止・手動実行・削除

ジョブを操作する基本コマンド
-- ジョブを有効化(CREATE_JOB で enabled=>FALSE にした場合)
EXEC DBMS_SCHEDULER.ENABLE('DAILY_CLEANUP_JOB');

-- ジョブを無効化(スケジュール実行を停止するが削除はしない)
EXEC DBMS_SCHEDULER.DISABLE('DAILY_CLEANUP_JOB');

-- ジョブを手動で今すぐ実行する(テスト・緊急実行)
EXEC DBMS_SCHEDULER.RUN_JOB('DAILY_CLEANUP_JOB');
-- use_current_session => FALSE にするとバックグラウンドで非同期実行
EXEC DBMS_SCHEDULER.RUN_JOB('DAILY_CLEANUP_JOB', use_current_session => FALSE);

-- 実行中のジョブを停止する
EXEC DBMS_SCHEDULER.STOP_JOB('DAILY_CLEANUP_JOB');

-- ジョブを削除する
EXEC DBMS_SCHEDULER.DROP_JOB('DAILY_CLEANUP_JOB');
-- プログラム・スケジュールも削除する
EXEC DBMS_SCHEDULER.DROP_PROGRAM('PRG_ARCHIVE_DATA');
EXEC DBMS_SCHEDULER.DROP_SCHEDULE('SCH_NIGHTLY_2AM');

ジョブの監視(DBA_SCHEDULER_JOBS・実行履歴)

ジョブの状態を確認する
-- 全ジョブの状態確認
SELECT
    job_name,
    state,              -- SCHEDULED / RUNNING / DISABLED / FAILED / SUCCEEDED
    enabled,
    last_start_date,
    last_run_duration,
    next_run_date,
    run_count,
    failure_count,
    retry_count
FROM DBA_SCHEDULER_JOBS
WHERE owner = 'MYSCHEMA'   -- スキーマ名を指定(自分のジョブは USER_SCHEDULER_JOBS で確認可能)
ORDER BY job_name;

-- 現在実行中のジョブを確認
SELECT
    owner,
    job_name,
    session_id,
    running_instance,
    elapsed_time
FROM DBA_SCHEDULER_RUNNING_JOBS;
ジョブの実行履歴とエラーを確認する
-- 実行履歴の確認(デフォルトで最新 30 件が保存される)
SELECT
    job_name,
    status,                 -- SUCCEEDED / FAILED
    error#,                 -- エラーコード(0 = 正常)
    actual_start_date,
    run_duration,
    additional_info         -- エラーの詳細メッセージ
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE owner = 'MYSCHEMA'
ORDER BY actual_start_date DESC
FETCH FIRST 20 ROWS ONLY;

-- 失敗したジョブだけを確認
SELECT
    job_name,
    status,
    error#,
    TO_CHAR(actual_start_date, 'YYYY-MM-DD HH24:MI:SS') AS start_time,
    additional_info
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE owner = 'MYSCHEMA'
  AND status = 'FAILED'
ORDER BY actual_start_date DESC;
ジョブのログ保持期間を調整する
DBA_SCHEDULER_JOB_RUN_DETAILS に保存される実行履歴の件数はlog_history で制御します(デフォルト 30 件)。
ジョブのログ保持件数を変更する
-- ジョブごとにログ保持件数を設定する
BEGIN
    DBMS_SCHEDULER.SET_ATTRIBUTE(
        name      => 'DAILY_CLEANUP_JOB',
        attribute => 'log_history',
        value     => 60    -- 直近 60 件の実行履歴を保存
    );
END;
/

-- 実行に失敗した場合にリトライ回数を設定する(デフォルト 0)
BEGIN
    DBMS_SCHEDULER.SET_ATTRIBUTE(
        name      => 'DAILY_CLEANUP_JOB',
        attribute => 'restartable',
        value     => TRUE    -- 失敗時にリスタート可能にする
    );
    DBMS_SCHEDULER.SET_ATTRIBUTE(
        name      => 'DAILY_CLEANUP_JOB',
        attribute => 'max_failures',
        value     => 3     -- 連続 3 回失敗したらジョブを無効化
    );
END;
/

DBMS_JOB(旧API)との違い

項目 DBMS_JOB(旧) DBMS_SCHEDULER(新)
スケジュール指定 次回実行時刻を計算する式(例: SYSDATE + 1/24) カレンダー式(FREQ=DAILY など)
実行内容 PL/SQL 文字列のみ PL/SQL ブロック・ストアドプロシージャ・外部スクリプト
実行履歴 なし DBA_SCHEDULER_JOB_RUN_DETAILS で確認可能
エラー処理 限定的 max_failures・restartable など豊富
確認方法 DBA_JOBS DBA_SCHEDULER_JOBS
推奨度 非推奨(互換性のためにのみ残存) 推奨

まとめ

  • CREATE_JOB:ジョブ名・実行内容(job_type/job_action)・スケジュール(repeat_interval)・enabled を指定して作成する
  • REPEAT_INTERVAL:カレンダー式で指定(FREQ=DAILY, BYHOUR, BYMONTHDAY など)。EVALUATE_CALENDAR_STRING で事前検証できる
  • プログラムとスケジュールの分離:CREATE_PROGRAM / CREATE_SCHEDULE で再利用性が高まる
  • RUN_JOB:手動実行でテストできる(use_current_session=FALSE で非同期実行)
  • DBA_SCHEDULER_JOB_RUN_DETAILS:実行履歴・エラーコード・additional_info でエラー原因を確認する

ジョブの状態確認・実行中ジョブの強制停止についてはOracleジョブの確認方法完全ガイドも参照してください。