miércoles, 18 de febrero de 2009

Migrar la programación de rutinas de DBMS_JOB a DBMS_SCHEDULER

La idea de hoy es mostrarles las ventajas que tiene usar el nuevo paquete DBMS_SCHEDULER y asi propiciar a que comiencen a migrar las rutinas programadas en la base usando DBMS_JOB. Este paquete esta actualmente en estado “Deprecated” y solo existe por cuestiones de compatibilidad hacia atrás. Oracle Corporation recomienda fuertemente la migración de toda la programación desde DBMS_JOB hacia DBMS_SCHEDULER.
Para comenzar a migrar se va a explicar un método simple para migrar bloques anónimos y procedimientos. Si bien la forma mas prolija y estructurada es armar entidades PROGRAMS y SCHEDULER y luego asociarlas por medio de un JOB, vamos enfocarnos en una solución más cercana a la forma de programación antigua (usando dbms_job) para que el impacto de cambio sea menor y así fomentar el uso de dbms_scheduler.

Comparación de programación con DBMS_JOB y DBMS_SCHEDULER
Para comparar los dos paquetes para programación de tareas vamos a usar dos ejemplos de uso común. Se va a programar un bloque anónimo y luego se mostrará como programar la ejecución de código almacenado en la base de datos.

Usando DBMS_JOB


Ejecución de Bloque Anónimo
DECLARE
    l_job int;
BEGIN
  DBMS_JOB.submit (
    job       => l_job,
    what      => '',
    next_date => trunc(SYSDATE)+22/24,
    interval  => 'trunc(SYSDATE+1) + 22/24');   

  COMMIT;
END;

Ejecución de procedimientos

DECLARE
    l_job int;
BEGIN
  DBMS_JOB.submit (
    job       => l_job,
    what      => 'procedimiento>',
    next_date => trunc(SYSDATE)+22/24,
    interval  => 'trunc(SYSDATE+1) + 22/24');   

  COMMIT;
END;

Usando DBMS_SCHEDULER
Ejecución de Bloque Anónimo

Opción 1: Intervalo definido como se define con DBMS_JOB (modalidad vieja)
BEGIN
  DBMS_SCHEDULER.create_job (
    job_name        => 'job_1',
    job_type        => 'PLSQL_BLOCK',
    job_action      => '',
    start_date      => trunc(SYSTIMESTAMP) + 22/24,
    repeat_interval => 'trunc(SYSTIMESTAMP+1) + 22/24',
    enabled => true);
END;

Opción 2: Intervalo definido de forma mas simple y comprensible (modalidad nueva)
BEGIN
  DBMS_SCHEDULER.create_job (
    job_name        => 'job_1',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN foo; END;',
    start_date      => trunc(SYSTIMESTAMP) + 22/24,
    repeat_interval => 'FREQ=DAILY;BYHOUR=22;BYMINUTE=0;BYSECOND=0',
    enabled => true);
END;

Como se ve en el ejemplo es muy sencillo definir los intervalos. Incluso se pueden definir días de la semana, días del mes, meses del año, etc. Para mayor detalle ver Calendaring Syntax en el manual “PL/SQL Packages and Types Reference 10g”

Ejecución de procedimientos

BEGIN
  DBMS_SCHEDULER.create_job (
    job_name        => 'job_1',
    job_type        => 'STORED_PROCEDURE',
    job_action      => '',
    start_date      => trunc(SYSTIMESTAMP) + 22/24,
    repeat_interval => 'FREQ=DAILY;BYHOUR=22;BYMINUTE=0;BYSECOND=0',
    enabled => true);
END;


Ventajas de usar DBMS_SCHEDULER

· Permite definir intervalos en forma mas expresiva y simple (Calendaring Sintax).

· Permite darle un nombre significativo al job. Con dbms_job se le asignaba un número interno del sistema.

· Se le puede definir prioridades de ejecución. Se pueden asociar ventanas de ejecución con planes de Resource Manager.

· Guarda registros historicos de detalle de ejecuciones, cantidad de corridas, errores, detalle de los errores, etc.

· Es mucho más sencillo matar un job programado desde dbms_scheduler que un job programado con dbms_job.


Consultas comunes para obtener información de programación DBMS_SCHEDULER

Para mostrar detalle de las corridas de los jobs:
select log_date,
       job_name,
       status,
       req_start_date,
       actual_start_date,
       run_duration
from   dba_scheduler_job_run_details

Para ver los jobs que están corriendo:
select job_name,
       session_id,
       running_instance,
       elapsed_time,
       cpu_used
from dba_scheduler_running_jobs;

Para ver detalle de como están definidos los jobs:
select job_name,
       job_creator,
       job_type,
       job_action,
       start_date,
       repeat_interval,
       next_run_date
       enabled,
       run_count,
       failure_count
from user_scheduler_jobs

5 comentarios:

  1. juan alejandro jualeop@gmail.com22 de julio de 2011, 15:08

    Muchas gracias por la información, tengo una duda, cómo se si el paquete DBMS_SCHEDULER está instalado en mi versión de oracle, existe algún select para validar esto??

    ResponderEliminar
  2. Muchas gracias, me ha servido de gran ayuda.

    ResponderEliminar
  3. Ven una pregunta, los DBMS_Jobs tenian la particularidad de que una vez se termina la ejecucion del proceso, estos son eliminados, esto permitia segmentar una reporte pesado, por ejemplo, en varias partes y manejarlos con varios user_jobs corriendo paralelamente y al finalizar el reporte todos los jobs eran eliminados y al ejecutarlo nuevamente se creaban nuevos jobs. Esto se puede hacer con DBMS_SCHEDULER?

    ResponderEliminar
  4. Pedro, claro que puedes hacer eso y mucho mas con dbms_scheduler. Para paralelizar como tu dices es ideal usar con dbms_schedureler los light weight jobs que se crear y eliminan mas eficientemente y requieren menos metadata. Te recomiendo la siguiente nota:
    http://www.oracle-base.com/articles/11g/scheduler-enhancements-11gr1.php#lightweight_jobs

    ResponderEliminar