ایجاد و مدیریت job با کمک بسته DBMS_JOB

برای انجام زمانبندی در سطح دیتابیس، دو بسته با نامهای dbms_job و dbms_scheduler موجود می باشند که بسته dbms_job از نسخه های قدیمی اوراکل ارائه شده و در نسخه های جدید هم کماکان مورد استفاده قرار می گیرد و بسته dbms_scheduler که در نسخه جدیدتر اوراکل عرضه شد، توانست تا حدود زیادی جایگزین مناسبی برای بسته dbms_job باشد.

دراین متن قصد داریم به بسته dbms_job بپردازیم.

آشنایی با پروسیجرهای مهم DBMS_JOB

این بسته به صورت built-in در دیتابیس موجود است و شامل پروسیجرها و فانکشنهای متنوعی می باشد که در ادامه در مورد هر یک از  آن ها، مطالبی را ارائه خواهیم کرد.

پروسیجر Submit

 این پروسیجر شامل چندین پارامتر می باشد که شرح هر یک به صورت مختصر در ادامه خواهد امد.

PROCEDURE submit (    

job       OUT BINARY_INTEGER,

what      IN  VARCHAR2,

next_date IN  DATE DEFAULT sysdate,

interval  IN  VARCHAR2 DEFAULT ‘null’,

no_parse  IN  BOOLEAN DEFAULT FALSE,

instance  IN  BINARY_INTEGER DEFAULT 0,

force     IN  BOOLEAN DEFAULT FALSE );

پارامتر Job: این پارامتر از نوع output می باشد که شماره job را برمی گرداند. برای اجرا و یا هرگونه تصرفی در job ایجاد شده، باید از این شماره استفاده کرد.

پارامتر what: مقدار ورودی این پارامتر، دستوری است که باید اجرا شود برای مثال، ورودی این پارامتر می تواند نام پروسیجر، فانکشن و … باشد.

مثال:

what  => ‘proc1;’

نکته: اگر دستور ورودی پارامتر what، حاوی تک کوتیشن(‘) باشد، باید این کوتیشن تکرار شود. مثال:

what  => ‘myproc(”10-JAN-99”, next_date, broken);’

what  => usef.emp.give_raise(JI, 400);’

پارامتر next_date: این پارامتر در هنگام ساخت job، زمان اولین اجرا را مشخص خواهد کرد و بعد از اولین اجرای جاب، اجرای دفعات بعدی هم توسط این پارامتر مشخص می شود. مقدار پیش فرض این پارامتر برابر با sysdate می باشد.

مثال:

next_date => to_date(’03-05-2017 14:58:18′, ‘dd-mm-yyyy hh24:mi:ss’)

پارامتر interval: این پارامتر مشخص می کند که تناوب زمانی اجرای job در اینده چگونه باشد. مقدار پیش فرض آن برابر با null می باشد.

مثال:

interval => ‘sysdate+1’

نکته: در مورد نحوه تنظیم تاریخ برای پارامترهای مذکور، استفاده از نکات زیر می تواند مفید باشد:

‘SYSDATE + 7’ => هر هفت روز یکبار

‘SYSDATE + 1/48’=>هر نیم ساعت یکبار

‘NEXT_DAY(TRUNC(SYSDATE), ”MONDAY”) + 15/24’ =>هر دوشنبه ساعت 3 بعدازظهر

‘NEXT_DAY(ADD_MONTHS(TRUNC(SYSDATE, ”Q”), 3), ”THURSDAY”)’=>اولین چهارشنبه هر ماه

مثال: نمونه ای از نحوه تعیین مقدار برای پارامتر interval:

variable x number;

execute bms_job.submit(:x,’pack.proc(”arg1”);’,sysdate,’sysdate+1′);

پارامتر no_parse: زمانی که این پارامتر برابر با false تنظیم شده باشد، شی ای که نام ان در قسمت what امده است، یکبار پارس خواهد شد(در هنگام ساخت job) همچنین مقدار true برای این پارامتر، مانع از پارس شدن آن شی خواهد شد.

مثال 1:اگر این پارامتر برابر با TRUE تنظیم شده باشد، با اجرای دستور زیر، خطایی در زمان ایجاد جاب دریافت نخواهیم کرد:

— no_parse=>true

declare

 job NUMBER ;

begin

dbms_job.submit(job => job, what => ‘obj_usef1;’,next_date => to_date(‘03-05-2017 14:58:18’, ‘dd-mm-yyyy hh24:mi:ss’),interval => ‘sysdate+1’,no_parse=>TRUE);

  commit;

end;

/

Done.

همچنین مقدار false برای این پارامتر، مانع از ایجاد جاب خواهد شد:

— no_parse=>false

PLS-00201: identifier ‘OBJ_USEF1’ must be declared

ORA-06512: at “SYS.DBMS_JOB”, line 116

پارامتر Instance: مقدار این پارامتر مشخص می کند که job مورد نظر در کدام یک از instanceها قابل اجرا و اصلاح می باشد. مقدار پیش فرض این پارامتر برابر با dbms_job.any_instance می باشد و می تواند در هر instanceای اجرا شود.

پارامتر force: پارامتر force در این پروسیجر مشخص می کند که شماره تعیین شده برای پارامتر instance باید معتبر باشد یا خیر؟! پس با کمک این پارامتر، اگر شماره instanceای که موجود نیست را به پارامتر instance نسبت دهیم، با خطایی مواجه نخواهیم شد.

در نهایت مثالی را از نحوه ایجاد job از طریق پروسیجر submit را مشاهده خواهید کرد.

مثال:

SQL> VARIABLE jobno number;

SQL>

SQL> BEGIN

  2     DBMS_JOB.SUBMIT(:jobno,

  3        ‘dbms_ddl.analyze_object(”TABLE”, ”USEF”, ”USEF_TBL”,  ”ESTIMATE”, NULL, 55);’ ,

  4        SYSDATE, ‘SYSDATE + 2’);

  5     COMMIT;

  6  END;

  7  /

در ادامه به دیگر پروسیجرهای این پکیج خواهیم پرداخت.

پروسیجر isubmit

 با استفاده از پروسیجر isubmit می توان jobای با شماره دلخواه ایجاد کرد.

  PROCEDURE isubmit    ( job       IN  BINARY_INTEGER,

                         what      IN  VARCHAR2,

                         next_date IN  DATE,

                         interval  IN  VARCHAR2 DEFAULT ‘null’,

                         no_parse  IN  BOOLEAN DEFAULT FALSE);

مثال: در مثال زیر، jobای با شماره 99 ایجاد خواهد شد:

BEGIN

DBMS_JOB.isubmit (

job => 99,

what => ‘usef_proc1(1);’,

next_date => SYSDATE,

interval => ‘SYSDATE + 1/24 /* 1 Hour */’);

COMMIT;

END;

/

پروسیجر remove

 برای حذف یک job باید شماره آن را به تنها ورودی این پروسیجر ارسال کرد البته برای حذف job در حال اجرا، باید ابتدا آن را متوقف نمود و سپس آن را حذف کرد.

PROCEDURE remove    ( job       IN  BINARY_INTEGER );

مثال:

execute dbms_job.remove(95);

commit;

همچنین می توان از بلاک زیر برای حذف همه jobها استفاده کرد:

declare

 job user_jobs.job%TYPE;

 CURSOR c IS  select job from user_jobs;

begin

    OPEN c;

    LOOP

        fetch c into job;

        exit when c%NOTFOUND;

        dbms_output.put_line(‘Removing job: ‘||job);

        dbms_job.remove(job);

    END LOOP;

    CLOSE c;

    commit;

end;

پروسیجر change

 برای تغییر هر کدام از ویژگی های job، می توان از این پروسیجر استفاده کرد که پارامترهای این پروسیجر تقریبا مشابه با پارامترهای پروسیجر submit می باشند.

PROCEDURE change    (job       IN  BINARY_INTEGER,

                        what      IN  VARCHAR2,

                        next_date IN  DATE,

                        interval  IN  VARCHAR2,

                       instance  IN  BINARY_INTEGER DEFAULT NULL,

                       force     IN  BOOLEAN DEFAULT FALSE);

نکته: بعد از هر تغییری باید از commit استفاده کرد.

پروسیجر what

تغییر مقدار پارامتر what برای یک job به خصوص، با کمک این پروسیجر قابل انجام است.

  PROCEDURE what( job       IN  BINARY_INTEGER,  what   IN  VARCHAR2 );

مثال:

BEGIN

DBMS_JOB.WHAT(99, ‘DBMS_DDL.ANALYZE_OBJECT(”TABLE”, ”USEF”, ”USEF_TBL2”,   ”ESTIMATE”, NULL, 50);’);

END;

پروسیجر next_date

 با استفاده از این پروسیجر می توان تاریخ اجرای بعدی job را تغییر داد.

  PROCEDURE next_date ( job IN  BINARY_INTEGER,  next_date IN  DATE     );

پروسیجر interval

 تناوب زمانی که یک job اجرا می شود را می توان با استفاده از این پروسیجر تغییر داد.

 PROCEDURE interval  ( job IN  BINARY_INTEGER, interval  IN  VARCHAR2 );

پروسیجر broken

استفاده از این پروسیجر سبب می شود تا job مربوطه هیچ گاه اجرا نشود. هر job بعد از 16  بار اجرای ناموفق به این حالت در خواهد امد(البته 16 بار اجرای ناموفق متوالی).

 PROCEDURE broken  ( job IN BINARY_INTEGER, broken IN BOOLEAN,next_date IN DATE DEFAULT SYSDATE );

مثال:

exec dbms_job.broken(job => 16,broken => true);

همچنین برای خروج از این حالت می توان زمان  بعدی اجرای آن job را مشخص کرد:

exec dbms_job.broken(job => 16,broken => false,next_date => NEXT_DAY(SYSDATE, ‘MONDAY’));

پروسیجرrun

 برای اجرای job به صورت دستی می توان از این پروسیجر استفاده کرد.

PROCEDURE run       ( job IN  BINARY_INTEGER, force IN  BOOLEAN DEFAULT FALSE);

نکته: حتی اگر job در حالت بروکن هم قرار داشته باشد، از طریق این پروسیجر قابل اجرا می باشد.

مثال:

execute dbms_job.run(14144);

پروسیجر user_export

 با استفاده از این پروسیجر، متن job از طریق شماره آن قابل مشاهده خواهد بود.

PROCEDURE user_export ( job IN BINARY_INTEGER, mycall IN OUT VARCHAR2);

مثال:

SQL> variable x varchar2;

SQL> exec dbms_job.user_export(3,:x);

dbms_job.isubmit(job=>3,what=>’proc1;’,next_date=>to_date(‘2017-05-04:14:15:36′,’YYYY-MM-DD:HH24:MI:SS’) ,interval=>’sysdate+1′, no_parse=>TRUE);

dbms_job و محیط RAC

در محیط RAC این قابلیت وجود دارد تا هر کدام از jobها را به یک instance خاص مقید کرد تا تنها به وسیله آن نود، job مورد نظر قابل اجرا و قابل تغییر باشد.

همانطور که قبلا بیان کردیم، برای تنظیم شماره instance، می توان از پروسیجر submit و یا instance استفاده کرد:

DBMS_JOB.SUBMIT(job,what,interval,no_parse,instance,force);

DBMS_JOB.INSTANCE(JOB,instance,force);

پارامتر force در این دو پروسیجر مشخص می کند که شماره تعیین شده برای پارامتر instance باید معتبر باشد یا نه؟! در صورت تنظیم این پارامتر به مقدار false، شماره instance باید واقعی باشد(به بیانی دیگر، الزاما باید نودی با این شماره وجود داشته باشد) در غیر این صورت، ایجاد job و یا تغییر آن با خطا متوقف خواهد شد البته استفاده از مقدار true، از این خطا جلوگیری خواهد کرد و این پارامتر هر مقدار مثبتی را پذیرا خواهد بود:

–true

SQL> exec dbms_job.instance(job => 16,instance => 50,force => true);

PL/SQL procedure successfully completed

–false

SQL> exec dbms_job.instance(job => 16,instance => 50,force => false);

ORA-23428: job associated instance number 50 is not valid

ORA-06512: at “SYS.DBMS_SYS_ERROR”, line 86

در این صورت، اگر job شماره 16 به صورت دستی اجرا شود، با خطا متوقف خواهد شد:

SQL> exec dbms_job.run(job => 16);

ORA-23428: job associated instance number 50 is not valid

مگر  آن که از عبارت force استفاده شود که در این صورت این job بر روی نودهای دیگر اجرا خواهد شد:

SQL> exec dbms_job.run(job => 16,force => true);

PL/SQL procedure successfully completed

مقدار پیش فرض این پارامتر برابر با صفر می باشد که به معنی همه نودها خواهد بود و استفاده از مقادیر null و یا منفی برای پارامتر instance سبب بروز خطا خواهد شد.

نکاتی در مورد dbms_job

نکته 1: تنها مالک job می تواند آن را اجرا و یا حذف کند همچنین هرگونه تغییر هم باید توسط owner جاب انجام شود.

نکته 2: شماره job از طریق sequenceای به نام JOBSEQ بدست می اید.

نکته 3: اجرای یک job از طریق job دیگر ممکن نیست.

نکته 4: در صورتی که مقدار پارامتر interval برابر با null تعیین شده باشد، job مورد نظر بعد از اولین اجرا، از لیست job queue خارج خواهد شد و با هر بار اجرای دستی ان، خطای زیر رخ خواهد داد:

ORA-23421: job number 88 is not a job in the job queue

ORA-06512: at “SYS.DBMS_SYS_ERROR”, line 86

ORA-06512: at “SYS.DBMS_IJOB”, line 781

ORA-06512: at “SYS.DBMS_JOB”, line 267

نکته 5: اطلاعات مربوط به dbms_jobs در جدول $jo$ ذخیره می شود و پروسس CJQ0 که مخفف coordinator job queue می باشد، مسئولیت دارد تا jobهای مربوطه را زیر نظر داشته باشد تا در صورت لزوم به کمک پروسس Jnnn ان job را اجرا کند.

در صورتی که پارامتر job_queue_processes برابر با صفر تنظیم شده باشد، این پروسسها اجرا نخواهند شد. برای بررسی خطاها و هشدارهای مربوط به این پروسس، باید در بین فایلهای تریس، به دنبال فایلی با فرمت SID-cjq0_nnnn.trc گشت.

[root@usef ~]# locate *cjq0*.trc

[root@usef ~]# less /u01/oracle/diag/rdbms/usef11g/usef11g/trace/usef11g_cjq0_11511.trc

نکته 6: از ویوهای مهم مربوط به این نوع از jobها، می توان به dba_jobs و dba_jobs_running اشاره کرد. پرس و جوهای زیر هم می تواند در این زمینه مفید باشد:

پرس و جوی 1:

SELECT SID, r.JOB, LOG_USER, r.THIS_DATE, r.THIS_SEC  FROM DBA_JOBS_RUNNING r, DBA_JOBS j  WHERE r.JOB = j.JOB;

پرس و جوی 2:

SELECT ‘Job:’|| job, WHAT, ‘Next:’|| to_char(NEXT_DATE,’dd-Mon-yyyy HH24:MI’), ‘ Last:’|| to_char(LAST_DATE,’dd-Mon-yyyy HH24:MI’), ‘ Broken:’|| BROKEN FROM dba_jobs;

نکته 7: در صورتی که فیلد LAST_DATE در ویوی DBA_JOBS برابر با null باشد و یا در صورتی که NEXT_DATE به صورت اتوماتیک در بازه زمانی تعیین شده تغییر نکند، نشانگر عدم اجرای این job به صورت خودکار خواهد بود.

نکته 8:  به صورت خلاصه، برای جلوگیری از عدم اجرای به موقع یک job باید نکات زیر را در نظر داشت:

1.پارامتر JOB_QUEUE_PROCESSES برابر با صفر تنظیم نشده باشد.

SQL> show parameter JOB_QUEUE_PROCESSES

job_queue_processes                  integer     4000

2. پارامتر _SYSTEM_TRIG_ENABLED به مقدار false تنظیم نشده باشد.

select a.ksppinm parameter,b.ksppstvl value from x$ksppi a,x$ksppcv b where a.indx=b.indx and ksppinm=’_system_trig_enabled’;

برای تنظیم مقدار این پارامتر به true می توان دستور زیر را اجرا کرد:

alter system set “_system_trig_enabled”=TRUE scope=both;

3. بانک اطلاعاتی در حالت RESTRICTED SESSIONS راه اندازی نشده باشد. برای خروج از این حالت، از دستور زیر استفاده می شود:

select logins from v$instance ;

alter system disable restricted session;

4. بلافاصله بعد از اصلاح job از commit استفاده شود.

5. job مورد نظر در حالت broken قرار نگرفته باشد.

select job,broken from dba_jobs where job=<job_number>;

6. ممکن است مقدار پارامتر مخفی job_queue_interval_ به مقداری غیر از مقدار پیش فرض که 5 ثانیه می باشد، تغییر کرده باشد.

select a.ksppinm parameter,b.ksppstvl value from x$ksppi a,x$ksppcv b where a.indx=b.indx and ksppinm=’_job_queue_interval’;

ارتباط با نویسنده مطلب:vahidusefzadeh@ کانال تخصصی اوراکل و لینوکس: OracleDB@

Comments (2)

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد.