「毎日深夜0時にバッチを動かしたい」「月次集計を自動化したい」——OracleにはDBMS_SCHEDULERというDB内蔵のジョブスケジューラがあります。本記事では基本的なジョブ作成から確認・実行・削除まで解説します。
目次
1. DBMS_SCHEDULERとは(DBMS_JOBとの違い) {#about}
| 比較項目 | DBMS_JOB(旧) | DBMS_SCHEDULER(新) |
|---|---|---|
| 導入バージョン | Oracle 7〜 | Oracle 10g〜 |
| スケジュール書式 | interval式(例:SYSDATE+1) | カレンダー式・CRON互換 |
| 外部スクリプト | 不可 | OSコマンド・シェルスクリプト実行可能 |
| ログ・監視 | 限定的 | 詳細なログ・アラート対応 |
| 推奨 | 非推奨(旧機能) | 現在の標準 |
本記事はDBMS_SCHEDULERを対象とします。
2. ジョブを作成する(CREATE_JOB) {#create-job}
PL/SQLブロックを実行するジョブ
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_DAILY_STATS', -- ジョブ名(大文字推奨)
job_type => 'PLSQL_BLOCK', -- PL/SQLブロックを実行
job_action => 'BEGIN update_daily_stats; END;', -- 実行するPL/SQL
start_date => SYSTIMESTAMP, -- 開始日時
repeat_interval => 'FREQ=DAILY; BYHOUR=0; BYMINUTE=0; BYSECOND=0', -- 毎日0:00
end_date => NULL, -- 終了日時(NULLは無期限)
enabled => TRUE, -- 作成と同時に有効化
comments => '毎日0時に日次統計更新を実行'
);
END;
/ストアドプロシージャを実行するジョブ
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_MONTHLY_REPORT',
job_type => 'STORED_PROCEDURE', -- ストアドプロシージャを実行
job_action => 'SCOTT.GENERATE_MONTHLY_REPORT', -- スキーマ名.プロシージャ名
repeat_interval => 'FREQ=MONTHLY; BYMONTHDAY=1; BYHOUR=2; BYMINUTE=0', -- 毎月1日2:00
enabled => TRUE,
comments => '毎月1日2時に月次レポートを生成'
);
END;
/OSコマンド・シェルスクリプトを実行するジョブ
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_SHELL_BACKUP',
job_type => 'EXECUTABLE', -- OSコマンドを実行
job_action => '/opt/oracle/scripts/backup.sh', -- スクリプトのフルパス
repeat_interval => 'FREQ=DAILY; BYHOUR=3; BYMINUTE=0',
enabled => TRUE,
comments => '毎日3時にバックアップスクリプトを実行'
);
END;
/3. ジョブの確認 {#check-job}
登録済みジョブの一覧
-- 自分のジョブを確認
SELECT
JOB_NAME,
JOB_TYPE,
ENABLED,
STATE,
LAST_START_DATE,
LAST_RUN_DURATION,
NEXT_RUN_DATE,
RUN_COUNT,
FAILURE_COUNT
FROM USER_SCHEDULER_JOBS
ORDER BY JOB_NAME;STATEの値:
| STATE | 意味 |
|---|---|
| SCHEDULED | 次回実行待ち(正常) |
| RUNNING | 現在実行中 |
| DISABLED | 無効化されている |
| CHAIN_STALLED | チェーンがスタック |
-- 全ユーザーのジョブを確認(DBA権限)
SELECT OWNER, JOB_NAME, STATE, NEXT_RUN_DATE, FAILURE_COUNT
FROM DBA_SCHEDULER_JOBS
ORDER BY OWNER, JOB_NAME;現在実行中のジョブを確認
SELECT JOB_NAME, SESSION_ID, RUNNING_INSTANCE, ELAPSED_TIME
FROM USER_SCHEDULER_RUNNING_JOBS;4. ジョブの手動実行・一時停止・削除 {#manage-job}
ジョブを今すぐ手動実行する
-- 即時実行(次回スケジュールには影響しない)
BEGIN
DBMS_SCHEDULER.RUN_JOB('JOB_DAILY_STATS');
END;
/ジョブを有効化・無効化
-- 無効化(スケジュール実行を止める)
BEGIN
DBMS_SCHEDULER.DISABLE('JOB_DAILY_STATS');
END;
/
-- 有効化
BEGIN
DBMS_SCHEDULER.ENABLE('JOB_DAILY_STATS');
END;
/ジョブの設定を変更
-- スケジュールを変更
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(
name => 'JOB_DAILY_STATS',
attribute => 'REPEAT_INTERVAL',
value => 'FREQ=DAILY; BYHOUR=1; BYMINUTE=0' -- 1:00に変更
);
END;
/
-- コメントを変更
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(
name => 'JOB_DAILY_STATS',
attribute => 'COMMENTS',
value => '毎日1時に日次統計更新を実行(変更済み)'
);
END;
/ジョブを削除
BEGIN
DBMS_SCHEDULER.DROP_JOB('JOB_DAILY_STATS');
END;
/
-- 実行中でも強制削除
BEGIN
DBMS_SCHEDULER.DROP_JOB(
job_name => 'JOB_DAILY_STATS',
force => TRUE
);
END;
/5. プログラムとスケジュールを分けて管理する {#program-schedule}
同じロジックを複数のスケジュールで使い回したい場合、「プログラム」と「スケジュール」を分けて定義できます。
-- プログラムの作成(処理内容)
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM(
program_name => 'PROG_DAILY_STATS',
program_type => 'STORED_PROCEDURE',
program_action => 'SCOTT.UPDATE_DAILY_STATS',
enabled => TRUE,
comments => '日次統計更新プロシージャ'
);
END;
/
-- スケジュールの作成(実行タイミング)
BEGIN
DBMS_SCHEDULER.CREATE_SCHEDULE(
schedule_name => 'SCH_EVERY_MIDNIGHT',
repeat_interval => 'FREQ=DAILY; BYHOUR=0; BYMINUTE=0; BYSECOND=0',
comments => '毎日0時'
);
END;
/
-- プログラムとスケジュールを組み合わせたジョブを作成
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_DAILY_STATS_V2',
program_name => 'PROG_DAILY_STATS',
schedule_name => 'SCH_EVERY_MIDNIGHT',
enabled => TRUE
);
END;
/6. スケジュールの設定パターン(CRON互換) {#cron}
| やりたいこと | REPEAT_INTERVAL |
|---|---|
| 毎日0時 | FREQ=DAILY; BYHOUR=0; BYMINUTE=0; BYSECOND=0 |
| 毎時0分 | FREQ=HOURLY; BYMINUTE=0; BYSECOND=0 |
| 毎週月曜日の9時 | FREQ=WEEKLY; BYDAY=MON; BYHOUR=9; BYMINUTE=0 |
| 毎月1日の3時 | FREQ=MONTHLY; BYMONTHDAY=1; BYHOUR=3; BYMINUTE=0 |
| 毎月末日の2時 | FREQ=MONTHLY; BYMONTHDAY=-1; BYHOUR=2; BYMINUTE=0 |
| 平日(月〜金)の8時 | FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=8 |
| 30分ごと | FREQ=MINUTELY; INTERVAL=30 |
-- 次回実行日時を確認してスケジュールが正しいか検証
SELECT DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(
'FREQ=WEEKLY; BYDAY=MON; BYHOUR=9; BYMINUTE=0',
NULL, SYSTIMESTAMP
) AS 次回実行日時
FROM DUAL;7. ジョブ実行ログの確認 {#log}
-- ジョブの実行履歴ログ
SELECT
JOB_NAME,
STATUS,
ACTUAL_START_DATE,
RUN_DURATION,
ADDITIONAL_INFO
FROM USER_SCHEDULER_JOB_LOG
WHERE JOB_NAME = 'JOB_DAILY_STATS'
ORDER BY ACTUAL_START_DATE DESC
FETCH FIRST 10 ROWS ONLY;STATUSの値:
| STATUS | 意味 |
|---|---|
| SUCCEEDED | 正常終了 |
| FAILED | エラー終了 |
| STOPPED | 手動停止 |
-- エラーの詳細を確認
SELECT JOB_NAME, ERROR# AS エラーコード, ADDITIONAL_INFO AS エラー詳細
FROM USER_SCHEDULER_JOB_LOG
WHERE STATUS = 'FAILED'
ORDER BY ACTUAL_START_DATE DESC;8. よくあるエラーと対処 {#errors}
ORA-27486:権限不足
ORA-27486: 不十分な特権です-- DBMS_SCHEDULERの実行権限を付与
GRANT CREATE JOB TO SCOTT;
GRANT MANAGE SCHEDULER TO SCOTT; -- ジョブ管理全般ジョブがFAILEDになる
-- エラー詳細を確認
SELECT ADDITIONAL_INFO FROM USER_SCHEDULER_JOB_LOG
WHERE JOB_NAME = 'JOB_DAILY_STATS' AND STATUS = 'FAILED'
ORDER BY ACTUAL_START_DATE DESC;プロシージャ名のスペルミスやスキーマ名の未指定が多い原因です。
ジョブが実行されない(DISABLED状態)
-- 有効化されているか確認
SELECT ENABLED FROM USER_SCHEDULER_JOBS WHERE JOB_NAME = 'JOB_DAILY_STATS';
-- 有効化する
EXEC DBMS_SCHEDULER.ENABLE('JOB_DAILY_STATS');9. まとめ:ジョブ管理チェックリスト {#summary}
作成時
□ ジョブ名は大文字・わかりやすい命名規則で統一
□ 作成後に RUN_JOB で手動実行して動作確認
□ EVALUATE_CALENDAR_STRING でスケジュールの次回実行日時を確認
運用時
□ USER_SCHEDULER_JOB_LOG を定期確認(STATUS=FAILED がないか)
□ FAILURE_COUNT が増えていたら原因を調査
□ 不要になったジョブは DROP_JOB で削除(有効ジョブが増えると管理が困難)
トラブル時
□ 手動で RUN_JOB 実行 → 成功すれば認証・プロシージャの問題ではない
□ ADDITIONAL_INFO でエラー詳細を確認
□ STATE=DISABLED になっていたら ENABLE で再有効化関連記事:









コメント