Oracle DatabaseのDBMS_SCHEDULERとは?ジョブの自動実行・定期スケジュール設定方法を解説

Oracle

Oracle Databaseでは、DBMS_SCHEDULERを使ってPL/SQL処理やストアドプロシージャなどのジョブを自動実行できます。毎日決まった時刻にバッチ処理を動かす、数分おきに監視処理を実行する、月末に集計処理を実行するといった定期処理を、データベース側でスケジュール管理できます。

DBMS_SCHEDULERは単純な時刻指定だけでなく、繰り返し実行、ジョブの有効化・無効化、実行履歴の確認、ジョブクラスやプログラム、スケジュールの分離など、業務システムのバッチ運用に必要な機能を幅広く備えています。

この記事では、Oracle DatabaseでDBMS_SCHEDULERを使ってジョブを自動スケジューリングする基本方法から、毎日・毎時・毎週の設定例、実行状況の確認、失敗時の調査、権限や運用上の注意点まで分かりやすく解説します。

DBMS_SCHEDULERでジョブを自動実行できる

DBMS_SCHEDULERは、Oracle Databaseに用意されているジョブスケジューリング機能です。指定した日時や繰り返し条件に従って、PL/SQLブロック、ストアドプロシージャ、プログラムなどを自動実行できます。

たとえば「毎日午前2時に売上集計処理を実行する」「10分おきにキューを確認する」「毎週月曜日にメンテナンス処理を行う」といった用途に利用できます。

OS側のcronやWindowsタスクスケジューラを使わず、Oracle Database内部で処理を完結させたい場合に特に便利です。

基本はDBMS_SCHEDULER.CREATE_JOBでジョブを作成する

もっとも基本的な方法は、DBMS_SCHEDULER.CREATE_JOBでジョブを作成することです。

たとえば、毎日午前2時にPROC_DAILY_SUMMARYというストアドプロシージャを実行する場合は、次のような形で設定できます。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_DAILY_SUMMARY',
    job_type        => 'STORED_PROCEDURE',
    job_action      => 'PROC_DAILY_SUMMARY',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY;BYHOUR=2;BYMINUTE=0;BYSECOND=0',
    enabled         => TRUE
  );
END;
/

この例では、JOB_DAILY_SUMMARYというジョブを作成し、PROC_DAILY_SUMMARYを毎日午前2時に実行する設定にしています。

repeat_intervalで毎日・毎時・毎週などを指定できる

DBMS_SCHEDULERでは、repeat_intervalにカレンダー式を指定して、柔軟な繰り返しスケジュールを定義できます。

代表的な例は次のとおりです。

目的 repeat_intervalの例
毎日2時 FREQ=DAILY;BYHOUR=2;BYMINUTE=0;BYSECOND=0
1時間ごと FREQ=HOURLY;INTERVAL=1
10分ごと FREQ=MINUTELY;INTERVAL=10
毎週月曜9時 FREQ=WEEKLY;BYDAY=MON;BYHOUR=9;BYMINUTE=0;BYSECOND=0
毎月1日0時 FREQ=MONTHLY;BYMONTHDAY=1;BYHOUR=0;BYMINUTE=0;BYSECOND=0

単純な「何分ごと」だけでなく、曜日や日付、時間帯まで組み合わせて設定できるため、業務バッチの多くをDBMS_SCHEDULERだけで管理できます。

PL/SQLブロックを直接ジョブとして登録することもできる

ストアドプロシージャをあらかじめ作成しなくても、job_typeにPLSQL_BLOCKを指定して、PL/SQLコードを直接ジョブとして登録できます。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_DELETE_OLD_LOG',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN DELETE FROM app_log WHERE created_at < SYSDATE - 90; COMMIT; END;',
    repeat_interval => 'FREQ=DAILY;BYHOUR=3;BYMINUTE=0;BYSECOND=0',
    enabled         => TRUE
  );
END;
/

この例では、90日より古いログを毎日午前3時に削除します。

ただし、複雑な処理を長いPL/SQLブロックとして直接埋め込むと保守しにくくなるため、実務では処理本体をプロシージャやパッケージへ分離し、ジョブから呼び出す設計のほうが管理しやすい場合があります。

ジョブを一度だけ実行することもできる

DBMS_SCHEDULERは定期実行専用ではありません。repeat_intervalを指定せず、start_dateだけを設定すれば、一度だけ実行するジョブも作成できます。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name   => 'JOB_ONE_TIME',
    job_type   => 'STORED_PROCEDURE',
    job_action => 'PROC_TEMP_MAINTENANCE',
    start_date => SYSTIMESTAMP + INTERVAL '1' HOUR,
    enabled    => TRUE,
    auto_drop  => TRUE
  );
END;
/

この例では、現在から1時間後に一度だけ処理を実行し、完了後にジョブを自動削除する構成です。

作成したジョブはENABLE・DISABLEで有効化と停止ができる

ジョブを一時的に止めたい場合、削除する必要はありません。DBMS_SCHEDULER.DISABLEを使って無効化できます。

BEGIN
  DBMS_SCHEDULER.DISABLE('JOB_DAILY_SUMMARY');
END;
/

再開する場合はENABLEを使用します。

BEGIN
  DBMS_SCHEDULER.ENABLE('JOB_DAILY_SUMMARY');
END;
/

メンテナンス期間だけ処理を止めたい場合や、障害調査中に定期ジョブを停止したい場合に便利です。

ジョブを今すぐ手動実行することもできる

スケジュール時刻を待たずにジョブをテストしたい場合は、DBMS_SCHEDULER.RUN_JOBを利用できます。

BEGIN
  DBMS_SCHEDULER.RUN_JOB(
    job_name            => 'JOB_DAILY_SUMMARY',
    use_current_session => TRUE
  );
END;
/

新しく作成したジョブの動作確認や、本番運用前のテストで利用できます。

use_current_sessionをTRUEにすると現在のセッションで実行されるため、エラーをその場で確認しやすくなります。

ジョブの一覧はUSER_SCHEDULER_JOBSなどで確認できる

作成したスケジューラジョブは、Oracleのデータディクショナリビューから確認できます。

SELECT job_name,
       enabled,
       state,
       repeat_interval,
       last_start_date,
       next_run_date
FROM user_scheduler_jobs;

USER_SCHEDULER_JOBSでは、自分のスキーマに作成されたジョブについて、現在の状態や次回実行日時などを確認できます。

管理者権限がある場合はALL_SCHEDULER_JOBSやDBA_SCHEDULER_JOBSを使って、他スキーマを含むジョブを確認することもできます。

実行結果やエラーはUSER_SCHEDULER_JOB_RUN_DETAILSで確認する

ジョブが正常に動作したかどうかを調べる場合は、実行履歴ビューを確認します。

SELECT job_name,
       status,
       actual_start_date,
       run_duration,
       error#,
       additional_info
FROM user_scheduler_job_run_details
ORDER BY log_date DESC;

statusにはSUCCEEDEDやFAILEDなどが表示されるため、ジョブが成功したのか失敗したのかを確認できます。

エラーが発生している場合は、ERROR#やADDITIONAL_INFOなども確認し、実行されたPL/SQL処理側のログと合わせて原因を調査します。

「ジョブを作ったのに実行されない」ときに確認するポイント

DBMS_SCHEDULERでジョブを作成しても動作しない場合、まずenabledがTRUEになっているか確認します。ジョブが無効化されていれば、予定時刻になっても実行されません。

次にUSER_SCHEDULER_JOBSのSTATEやNEXT_RUN_DATEを確認します。スケジュール条件が想定と違っていないか、次回実行日時が正しいかを確認できます。

さらに、ジョブ内で呼び出しているプロシージャやテーブルに必要な権限があるかも重要です。DBMS_SCHEDULERのジョブ実行環境では、ロール経由の権限ではなく直接付与された権限が必要になるケースがあるため、権限エラーが発生した場合は実行ユーザーの権限を確認します。

CREATE JOB権限が必要になる

自分のスキーマにジョブを作成するには、通常はCREATE JOBシステム権限が必要です。

別ユーザーのスキーマにジョブを作成するなど、より広い操作を行う場合はCREATE ANY JOBなど、追加の権限が必要になる場合があります。

本番環境では、必要以上に強い権限を付与せず、ジョブを実行する専用ユーザーやスキーマを用意する設計も検討すると安全です。

DBMS_SCHEDULERとDBMS_JOBの違い

Oracle Databaseには、古くからDBMS_JOBというジョブ実行機能も存在します。ただし、より高機能なスケジューリングや管理を行う場合はDBMS_SCHEDULERが中心になります。

機能 DBMS_SCHEDULER DBMS_JOB
定期ジョブ 対応 対応
複雑なカレンダー式 対応 限定的
ジョブクラス 対応 非対応
プログラム・スケジュール分離 対応 非対応
詳細な実行履歴 充実 限定的

新しくジョブ管理を設計する場合は、DBMS_SCHEDULERの利用を検討するのが一般的です。

プログラムとスケジュールを分離して再利用できる

小規模な処理ならCREATE_JOBだけで十分ですが、ジョブ数が増えてくると、実行内容とスケジュールを別オブジェクトとして管理すると分かりやすくなります。

DBMS_SCHEDULERではCREATE_PROGRAMで実行内容を定義し、CREATE_SCHEDULEで日時条件を定義し、それらをCREATE_JOBから組み合わせることができます。

たとえば同じ集計プログラムを「毎日」「月末」「手動検証用」など複数のスケジュールで動かす場合、プログラム部分を再利用できるため運用が整理しやすくなります。

毎日深夜にバッチ処理を動かす実践例

実務でよくあるのが、日中に蓄積されたデータを深夜に集計するバッチ処理です。

たとえばPROC_DAILY_SALESというプロシージャを毎日午前1時30分に動かす場合は、次のように設定できます。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_DAILY_SALES',
    job_type        => 'STORED_PROCEDURE',
    job_action      => 'PROC_DAILY_SALES',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY;BYHOUR=1;BYMINUTE=30;BYSECOND=0',
    enabled         => TRUE,
    comments        => '日次売上集計'
  );
END;
/

このようにコメントも登録しておけば、後から運用担当者がジョブの用途を確認しやすくなります。

10分おきの監視処理を設定する例

一定間隔で処理したい場合はINTERVALを利用できます。

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_QUEUE_CHECK',
    job_type        => 'STORED_PROCEDURE',
    job_action      => 'PROC_QUEUE_CHECK',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=MINUTELY;INTERVAL=10',
    enabled         => TRUE
  );
END;
/

この例ではPROC_QUEUE_CHECKが10分おきに実行されます。

ただし、1回の処理時間が実行間隔より長くなる可能性がある場合は、重複実行や処理遅延が発生しない設計になっているか確認する必要があります。

タイムゾーンを意識してstart_dateを設定する

運用環境によってはタイムゾーンも重要です。特にクラウド環境や海外拠点をまたぐシステムでは、「午前2時」がどのタイムゾーンを基準にしているのかを明確にする必要があります。

SYSTIMESTAMPはタイムゾーン情報を含むため、start_dateを設定するときはデータベースやセッションのタイムゾーン設定を確認しておくと安全です。

サマータイムがある地域や複数国で利用するシステムでは、単純な時刻だけでなく業務上の基準タイムゾーンを決めて運用することが重要です。

ジョブ削除はDROP_JOBで行う

不要になったジョブはDBMS_SCHEDULER.DROP_JOBで削除できます。

BEGIN
  DBMS_SCHEDULER.DROP_JOB(
    job_name => 'JOB_DAILY_SUMMARY'
  );
END;
/

一時停止ならDISABLE、完全に不要ならDROP_JOBというように使い分けます。

本番環境では、削除前にジョブ定義やrepeat_interval、job_actionなどを保存しておくと、誤削除時の復旧が容易になります。

本番運用ではジョブ内にエラー処理とログを用意する

DBMS_SCHEDULER自体にも実行履歴はありますが、業務処理の詳細な状況まで把握するには、アプリケーション側のログテーブルを用意すると便利です。

たとえば処理開始時刻、終了時刻、対象件数、成功・失敗、エラーメッセージなどを独自ログへ保存しておけば、「ジョブ自体は起動したが途中の1000件目で失敗した」といった状況も追跡できます。

また、例外を握りつぶして正常終了扱いにしてしまうと、Scheduler側ではSUCCEEDEDと表示される可能性があります。重大なエラーは適切にRAISEし、運用側から失敗を検知できる設計にすることが大切です。

トランザクションとCOMMITの扱いにも注意する

DBMS_SCHEDULERから実行される処理でINSERT、UPDATE、DELETEを行う場合は、トランザクション設計も重要です。

たとえば大量データを更新する処理で、どの単位でCOMMITするのか、途中で失敗したときに全件ROLLBACKするのか、一部だけ再実行可能にするのかを決めておく必要があります。

ジョブのスケジュール設定だけが正しくても、業務処理側のトランザクション設計が曖昧だと、障害時の復旧が難しくなるため注意してください。

DBMS_SCHEDULERが向いているケース

Oracle Database内で完結する処理を定期的に実行する場合、DBMS_SCHEDULERは非常に相性がよい機能です。

処理例 利用しやすさ
日次・月次集計 非常に向いている
古いデータの削除 向いている
PL/SQLバッチ処理 非常に向いている
定期的なステータス更新 向いている
複雑な外部システム連携 構成によっては外部ジョブ管理製品も検討
複数サーバーをまたぐ大規模ワークフロー 専用スケジューラとの比較が必要

データベース内部処理だけであればDBMS_SCHEDULERでシンプルに管理できますが、複数システムをまたぐ処理依存関係が多い場合は、Hinemos、JP1、Systemwalkerなどの外部ジョブ管理製品やクラウドのワークフロー機能と役割分担する場合もあります。

まとめ:Oracle DatabaseではDBMS_SCHEDULERで自動スケジューリングできる

Oracle Databaseでは、DBMS_SCHEDULERを利用してジョブの自動実行・定期スケジューリングを行えます。毎日、毎週、毎月、数分おきといった繰り返し条件を設定でき、PL/SQLブロックやストアドプロシージャなどを指定時刻に自動実行できます。

基本的にはDBMS_SCHEDULER.CREATE_JOBでジョブを作成し、repeat_intervalで実行周期を設定します。またENABLE・DISABLEによる停止と再開、RUN_JOBによる手動実行、USER_SCHEDULER_JOBSやUSER_SCHEDULER_JOB_RUN_DETAILSによる状態・履歴確認も可能です。

実務で利用する場合は、単にスケジュールを作るだけでなく、実行ユーザーの権限、タイムゾーン、重複実行、トランザクション、エラー処理、ログ、再実行方法まで設計しておくことが重要です。

Oracle Database内部で完結する日次・月次バッチや定期メンテナンス処理であれば、DBMS_SCHEDULERは標準機能だけで堅牢な自動運用を構築できる代表的な選択肢です。

コメント

タイトルとURLをコピーしました