Executive Summary: Modernizing Legacy DBMS_JOB Infrastructure
or decades, developers and DBAs used the DBMS_JOB package to schedule background tasks and recurring PL/SQL procedures. While DBMS_JOB remains supported for backward compatibility in Oracle Database 19c and 23ai, Oracle strongly recommends migrating all legacy jobs to DBMS_SCHEDULER.
DBMS_JOB suffers from major architectural drawbacks:
- Limited Concurrency: All jobs compete for a fixed pool of background processes defined by
JOB_QUEUE_PROCESSES. - Error-Prone Interval Math: Recurring schedules rely on
SYSDATEdate arithmetic (e.g.,TRUNC(SYSDATE + 1) + 2/24), which causes execution time drift over time. - Zero Execution Visibility: Failed jobs silently increment failure counts without recording execution error trace history.
DBMS_SCHEDULER addresses all these flaws by providing rich logging, calendar-based scheduling syntax (FREQ=DAILY;BYHOUR=2), resource manager integration, and external OS script execution.
Technical Architecture & Conversion Flow
<div class="process-flow">
<div class="process-step">
<div class="step-number">Phase 1</div>
<div class="step-title">Audit Active DBMS_JOB Tasks (DBA_JOBS)</div>
</div>
<div class="process-arrow">➔</div>
<div class="process-step">
<div class="step-number">Phase 2</div>
<div class="step-title">Convert PL/SQL & Repeat Interval</div>
</div>
<div class="process-arrow">➔</div>
<div class="process-step">
<div class="step-number">Phase 3</div>
<div class="step-title">Drop Legacy Job & Verify SCHEDULER Log</div>
</div>
</div>
⚖️ Side-by-Side Syntax Comparison Matrix
| Operations / Functionality | Legacy DBMS_JOB Package |
Modern DBMS_SCHEDULER Package |
|---|---|---|
| Create / Submit Job | DBMS_JOB.SUBMIT(job, what, next_date, interval) |
DBMS_SCHEDULER.CREATE_JOB(job_name, job_type, job_action, repeat_interval) |
| Schedule Syntax | Date math: SYSDATE + 1, TRUNC(SYSDATE)+7 |
Calendar syntax: FREQ=DAILY;BYHOUR=2;BYMINUTE=0 |
| Modify Attribute | DBMS_JOB.CHANGE(job, what, next_date, interval) |
DBMS_SCHEDULER.SET_ATTRIBUTE(name, attribute, value) |
| Run Immediate | DBMS_JOB.RUN(job) |
DBMS_SCHEDULER.RUN_JOB(job_name) |
| Remove / Drop Job | DBMS_JOB.REMOVE(job) |
DBMS_SCHEDULER.DROP_JOB(job_name) |
| Catalog View | USER_JOBS / DBA_JOBS |
USER_SCHEDULER_JOBS / DBA_SCHEDULER_JOBS |
| Execution Log View | None (Only failure count) | DBA_SCHEDULER_JOB_RUN_DETAILS |
🔍 Diagnostic Checklist: Audit Legacy DBMS_JOB Tasks
Run this diagnostic query in SQL*Plus or SQL Developer as SYS or a DBA user to locate all active legacy jobs requiring migration:
-- Query active legacy DBMS_JOB tasks across the database
SELECT
job,
log_user,
priv_user,
last_date,
next_date,
broken,
failures,
what AS job_action,
interval AS legacy_interval
FROM dba_jobs
ORDER BY job;
Step-by-Step Conversion Runbook: Concrete Code Example
Scenario
We have a legacy nightly data purge procedure app_owner.purge_stale_audit_logs that runs every night at 2:00 AM.
1. Legacy Implementation (DBMS_JOB)
-- Legacy DBMS_JOB Submission Script (DEPRECATED)
DECLARE
v_job_id NUMBER;
BEGIN
DBMS_JOB.SUBMIT(
job => v_job_id,
what => 'BEGIN app_owner.purge_stale_audit_logs; END;',
next_date => TRUNC(SYSDATE + 1) + 2/24,
interval => 'TRUNC(SYSDATE + 1) + 2/24'
);
COMMIT;
DBMS_OUTPUT.PUT_LINE('Submitted Legacy Job ID: ' || v_job_id);
END;
/
2. Modernized Implementation (DBMS_SCHEDULER)
-- Modernized DBMS_SCHEDULER Job Definition
BEGIN
-- Create the Scheduler Job
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'PURGE_STALE_AUDIT_LOGS_JOB',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN app_owner.purge_stale_audit_logs; END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0; BYSECOND=0',
enabled => TRUE,
comments => 'Nightly audit log purge procedure - Migrated from DBMS_JOB'
);
END;
/
💡 Key Improvement: Setting
repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0; BYSECOND=0'guarantees the job runs at exactly 2:00:00 AM every night regardless of how long the previous run took.
3. Decommission Legacy Job & Verify Migration
Once the new DBMS_SCHEDULER job is enabled:
-- Step A: Remove the legacy job from DBMS_JOB queue (Replace 42 with your job ID)
BEGIN
DBMS_JOB.REMOVE(42);
COMMIT;
END;
/
-- Step B: Force an immediate test execution of the new Scheduler job
BEGIN
DBMS_SCHEDULER.RUN_JOB('PURGE_STALE_AUDIT_LOGS_JOB');
END;
/
-- Step C: Inspect execution status and detailed log history
SELECT
job_name,
status,
error#,
actual_run_date,
run_duration,
output
FROM dba_scheduler_job_run_details
WHERE job_name = 'PURGE_STALE_AUDIT_LOGS_JOB'
ORDER BY actual_run_date DESC;
📚 Official Documentation & Technical References
- Oracle Database PL/SQL Packages Reference: DBMS_SCHEDULER Package Guide — Official API specifications, subprograms, and attributes for DBMS_SCHEDULER.
- Oracle Database Administrator’s Guide: Scheduling Jobs with Oracle Scheduler — Architecture, repeat interval syntax, and job execution management.
- ORACLE-BASE: DBMS_SCHEDULER in Oracle Database — Tim Hall’s guide to creating jobs, schedules, and migrating legacy DBMS_JOB definitions.
Need assistance auditing legacy database codebases or modernizing Oracle 19c/23ai job scheduling infrastructure? Contact our Database Specialists or explore our Enterprise Health Audits.