برای انجام زمانبندی در سطح دیتابیس، دو بسته با نامهای dbms_job و dbms_scheduler موجود می باشند که بسته dbms_job از نسخه های قدیمی اوراکل ارائه شده و در نسخه های جدید هم کماکان مورد استفاده قرار می گیرد و بسته dbms_scheduler که در نسخه جدیدتر اوراکل عرضه شد، توانست تا حدود زیادی جایگزین مناسبی برای بستهdbms_job باشد.
در این متن، قصد داریم به بسته dbms_scheduler بپردازیم.
آشنایی با پروسیجرهای مهم DBMS_SCHEDULER
این بسته همانند بسته dbms_job، قابلیت اجرای خودکار دستورات، توابع و پروسیجرها را دارا می باشد و علاوه بر آن ، امکان اجرای خودکار اسکریپت را نیز در سطح سیستم عامل فراهم می کند.
به عبارت دقیق تر، این نوع از jobها، در سه سطح قابل ایجاد می باشند:
1.STORED_PROCEDUR: توابع و پروسیجر به کمک این نوع job قابل اجرا می باشند.
2.PL/SQL block: اجرای anonymous block از طریق این نوع از jobها قابل انجام می باشد.
3.EXECUTABLE: برای اجرای اسکریپتی که بر روی سیستم عامل موجود است، می توان از این نوع job بهره گرفت.
بسته DBMS_SCHEDULER شامل پروسیجر و فانکشنهای متنوعی می باشد که در ادامه مهمترین آن ها را با محوریت job، program، schedule و window مورد بررسی قرار خواهیم داد.
JOB و آشنایی با پروسیجر create_job
اینکه چه برنامه ای، در چه زمانی و با چه تناوب زمانی اجرا شود، توسط job تعیین خواهد شد برای ایجاد یک job، می توان از پروسیجر create_job استفاده کرد.
در جدول زیر، اسامی پارامترهای این پروسیجر را مشاهده می کنید:
در ادامه مثالهایی از نحوه ایجاد انواع مختلف job را با هم مرور خواهیم کرد.
مثال 1: ایجاد job از نوع PL/SQL block
begin
sys.dbms_scheduler.create_job(job_name => ‘SYS.JOBJOB’,
job_type => ‘PLSQL_BLOCK’,
job_action =>
‘declare
a number:=0;
begin
for i in 1..100 loop
a:=a+1;
dbms_lock.sleep(a);
end loop;
end;’,
start_date => to_date(null),
repeat_interval => ‘Freq=Minutely;Interval=5’,
end_date => to_date(null),
job_class => ‘DEFAULT_JOB_CLASS’,
enabled => true,
auto_drop => false,
comments => ”);
end;
/
مثال 2: ایجاد job از نوع STORED_PROCEDUR
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => ‘update_sales’,
job_type => ‘STORED_PROCEDURE’,
job_action => ‘OS.SALES_PKG.UPDATE_SALES_SUMMARY’,
start_date => ‘to_date(’24-05-2017 00:00:00’, ‘dd-mm-yyyy hh24:mi:ss’)’,
repeat_interval => ‘FREQ=DAILY;INTERVAL=2’,
end_date => to_date(null),
auto_drop => FALSE
);
END;
/
مثال 3: ایجاد job از نوع EXECUTABLE
–متن اسکریپتی که در سیستم عامل قرار دارد:
/u01/job.sh
#!/bin/sh
export ORACLE_BASE=/u01/oracle
export ORACLE_HOME=/u01/oracle/11g
export ORACLE_SID=humtesti
export PATH=$ORACLE_HOME/bin:$PATH
/u01/oracle/11g/bin/rman target / <<EOF
run
{
backup database format ‘/u01/oracle/back/yyy%U’;
}
EOF
–ساخت جابی که قرار است این اسکریپت را اجرا کند:
begin
sys.dbms_scheduler.create_job(job_name => ‘SYS.JB2’,
job_type => ‘EXECUTABLE’,
job_action => ‘/u01/job.sh’,
start_date => to_date(’24-05-2017 00:00:00′, ‘dd-mm-yyyy hh24:mi:ss’),
repeat_interval => ‘Freq=Weekly;Interval=1;ByDay=Fri’,
end_date => to_date(null),
job_class => ‘AUTO_TASKS_JOB_CLASS’,
enabled => true,
auto_drop => false,
comments => ”);
end;
نکاتی در مورد external job
external job از طریق پروسس extjob اجرا می شود و اجرای external job توسط کاربر غیر sys، به دو روش زیر قابل تصور است:
روش اول: تغییر کاربر و گروهی که می تواند external job را ایجاد کند.
$ORACLE_HOME/rdbms/admin/externaljob.ora
run_user=oracle
run_group=oinstall
روش دوم: ایجاد credential برای کاربر با تعیین پسورد کاربر اورکل:
exec dbms_scheduler.create_credential(credential_name => ‘EXTERNAL_JOBS’,username => ‘oracle’, password => ‘o’);
برای مشاهده لیست ویوهای مربوط به credentialها می توان از ویوی dba_scheduler_credentials استفاده شود.همچنین می توان برای حذف این credential، از دستور زیر استفاده کرد:
exec dbms_scheduler.drop_credential(credential_name => ‘EXTERNAL_JOBS’);
مثالی از تنظیم یک credential برای یک جاب را در قسمت زیر می بینید:
begin
sys.dbms_scheduler.set_attribute(name =>’JB2′ ,attribute => ‘credential_name’,value=>’credential1′);
end;
آشنایی با دیگر پروسیجرهای بسته DBMS_SCHEDULER
در ادامه به صورت خلاصه نکاتی را در مورد شیوه مدیریت jobهای ایجاد شده با کمک پرسیجرهای بسته dbms_schedulaer را مرور می کنیم:
—برای اجرای دستی jobها باید از پروسیجر run_job استفاده کرد:
exec dbms_scheduler.run_job(job_name => ‘JOB_USEF’);
نکته:استفاده از پارامتر use_current_session در پروسیجر run_job سبب می شود session جاری تا اتمام اجرای job به کاربر بر نگردد البته در صورتی که این پارامتر برابر با false باشد، job مورد نظر در پس زمینه اجرا خواهد شد و session به کاربر برخواهد گشت. همچنین اجرای جاب با کمک use_current_session تاثیری در مقدار پارامتر failure_count و یا run_count نخواهد داشت.
—برای متوقف کردن job در حال اجرا، می توان از پروسیجر stop_job استفاده کرد:
exec dbms_scheduler.stop_job(job_name => ‘JOB_USEF’);
—برای حذف job، از پروسیجر drop_job استفاده می شود:
exec dbms_scheduler.drop_job(job_name => ‘JOB_USEF’);
—پروسیجرهای enable و disable برای فعال و غیرفعالسازی jobها قابل استفاده می باشند(البته وضعیت مولفه های دیگر نظیر program، schedule و … نیز به وسیله این دو پروسیجر قابل تغییر خواهد بود):
exec dbms_scheduler.disable(name => ‘JOB_USEF’,force => TRUE);
exec dbms_scheduler.enable(name => ‘JOB_USEF’);
—با استفاده از پروسیجر copy_job می توان job موجود در بانک را با نام جدیدی کپی کرد که در این صورت، job جدید به صورت پیش فرض غیرفعال می باشد.
exec dbms_scheduler.copy_job(old_job => ‘JOB_USEF’,new_job => ‘JOB_USEF_OLD’ );
—برای تغییر خصوصیات فعلی jobها می توان از پروسیجر set_attribute استفاده کرد. مثال:
begin
dbms_scheduler.set_attribute (
name => ‘run_load_sales’,
attribute => ‘repeat_interval’,
value => ‘freq=daily; byhour=3’);
end;
/
بررسی وضعیتهای مختلف یک job
بعد از ایجاد یک جاب، نیاز است تا بدانیم که این جاب در چه وضعیتی قرار دارد. تعیین وضعیت فعلی job، از طریق ویوی dba_scheduler_jobs و با کمک فیلد state قابل مشاهده خواهد بود.
جابها می توانند در یکی از وضعیتهای زیر قرار داشته باشند:
DISABLED : جاب در وضعیت غیرفعال قرار دارد و به صورت خودکار اجرا نخواهد شد.
FAILED: اجرای جاب با خطا متوقف شده است و قرار نیست که دیگر این جاب به صورت خودکار اجرا شود.
SCHEDULED: قابلیت اجرای خودکار برای جاب وجود دارد و در interval بعدی اجرا خواهد شد.
RUNNING: جاب در حال اجرا می باشد.
SUCCEEDED: جاب به صورت کامل اجرا شده و دیگر اجرا نخواهد شد.
BROKEN : یک job ممکن است به دلیل اجرای ناموفق، در وضعیت broken قرار بگیرد البته تعداد اجرای ناموفق آن باید از مقدار تعیین شده برای MAX_FAILURES بیشتر باشد.
Stopped: جاب قبلا در حال اجرا بوده و متوقف شده است و قرار است تنها یکبار اجرا شود.
schedule
زمان انجام(when) و نیز تناوب زمانی(interval) اجرای jobها، از طریق schedule قابل تعیین خواهد بود.
در روش قبلی این کار از طریق پارامترهای start_date،repeat_interval ، end_date انجام می شد در صورتی که می توان به جای تعیین این پارامترها، از پارامتر دیگری به نام schedule_name استفاده کرد.
برای انجام این کار، ابتدا باید Scheduleای ایجاد کرد و سپس از ان schedule برای این پارامتر بهره گرفت از مزیتهای schedule می توان به استفاده همزمان ان در چندین job مختلف اشاره کرد.
مثال: در این مثال، نحوه ایجاد job با کمک schedule را مشاهده خواهید کرد:
begin
sys.dbms_scheduler.create_schedule(schedule_name => ‘USEF.SCHEDULE1’,
start_date => to_date(’22-06-2017 00:00:00′, ‘dd-mm-yyyy hh24:mi:ss’),
repeat_interval => ‘Freq=Minutely;Interval=10’,
end_date => to_date(null),
comments => ”);
end;
/
begin
sys.dbms_scheduler.create_job(job_name => ‘USEF.JOB1’,
job_type => ‘PLSQL_BLOCK’,
job_action => ‘pr1;’,
schedule_name => ‘USEF.SCHEDULE1’,
job_class => ‘AUTO_TASKS_JOB_CLASS’,
enabled => true,
auto_drop => false,
comments => ”);
end;
/
-برای حذف یک Schedule، باید از پروسیجر drop_schedule استفاده کرد:
BEGIN
DBMS_SCHEDULER.drop_schedule(schedule_name =>‘USEF.SCHEDULE1’);
END;
/
—برای تغییر خصوصیات فعلی یک Schedule می توان از پروسیجر set_attribute استفاده کرد.
—برای مشاهده اسامی scheduleها، می توان از ویوی dba_scheduler_schedules استفاده کرد.
program
Jobای که ایجاد می شود، باید چه عملی(job action) را انجام دهد؟، با ساخت program می توان به این سوال پاسخ داد.
در روش قبلی(در پروسیجر create_job)، پاسخ به این سوال با کمک پارامترهای job_type و job_action انجام می شد. program روش دیگری برای پاسخ دادن به این سوال می باشد که در این صورت، در هنگام ساخت job از پارامتر program_name به جای پارامترهای مذکور استفاده می شود.
—همانند schedule می توان از program هم استفاده چند باره داشت.
—برای ایجاد program، باید از پروسیجر create_program استفاده کرد.
مثال: در این مثال نحوه ایجاد job با کمک program را مشاهده خواهید کرد:
begin
sys.dbms_scheduler.create_program(program_name => ‘USEF.PROGRAM1’,
program_type => ‘PLSQL_BLOCK’,
program_action => ‘pr1;’,
number_of_arguments => 0,
enabled => true,
comments => ”);
end;
/
begin
sys.dbms_scheduler.create_job(job_name => ‘USEF.JOB1’,
program_name => ‘USEF.PROGRAM1’,
start_date => to_date(’22-06-2017 00:00:00′, ‘dd-mm-yyyy hh24:mi:ss’),
repeat_interval => ‘Freq=Hourly;Interval=1’,
end_date => to_date(null),
job_class => ‘AUTO_TASKS_JOB_CLASS’,
enabled => true,
auto_drop => false,
comments => ”);
end;
/
—برای تغییر خصوصیات فعلی یک program می توان از پروسیجر set_attribute استفاده کرد.
—برای مشاهده لیست programها، می توان از ویوی dba_scheduler_programs استفاده کرد.
—برای استفاده از یک program توسط یک کاربر، کاربر مورد نظر یا باید مالک ان program باشد و یا اینکه مجوز execute ان را دارا باشد.
آرگومان
فرض کنید از پروسیجری استفاده می کنیم که شامل پارامتر ورودی می باشد، برای استفاده از این پروسیجر در یک job می توان هر کدام از این پارامترهای ورودی را تحت یک ارگومان به این پروسیجر پاس داد.
برای انجام این کار، باید در هنگام ساخت program، تعداد آرگومان ها را با استفاده از پارامتر number_of_arguments مشخص کرد و در نهایت با استفاده از پروسیجر define_program_argument، آرگومان ورودی را به آن ارسال کرد.
در ادامه دو مثال از نحوه ایجاد program که دارای آرگومان نیز می باشند، را مشاهده خواهید کرد.
مثال 1: آرگومان در این مثال مربوط به پروسیجر می باشد.
begin
DBMS_SCHEDULER.create_program (
program_name => ‘test_stored_procedure_prog’,
program_type => ‘STORED_PROCEDURE’,
program_action => ‘DBMS_STATS.gather_schema_stats’,
number_of_arguments => 1,
enabled => FALSE
);
end;
/
begin
DBMS_SCHEDULER.define_program_argument (
program_name => ‘test_stored_procedure_prog’,
argument_name => ‘ownname’,
argument_position => 1,
argument_type => ‘VARCHAR2’,
default_value => ‘USEF’);
DBMS_SCHEDULER.enable (name => ‘test_stored_procedure_prog’);
END;
/
مثال 2: در این مثال، آرگومان مربوط به external job می باشد که در نتیجه اجرای آن، دستور(/bin/ls /u07/) اجرا خواهد شد.
BEGIN
DBMS_SCHEDULER.create_job(
job_name => ‘e5’,
job_type => ‘EXECUTABLE’,
number_of_arguments => 1,
job_action => ‘/bin/ls’,
auto_drop => FALSE,
enabled => FALSE);
DBMS_SCHEDULER.set_job_argument_value(‘e5′,1,’/u07’);
DBMS_SCHEDULER.enable(‘e5’);
END;
/
—برای مشاهده لیست آرگومان ها می توان از ویوی dba_scheduler_program_args استفاده کرد.
Job Class
با استفاده از job class می توان jobهایی با خصوصیتهای مشابه و نزدیک به هم را در یک گروه مجزا قرار داد و در مورد آنها سیاستهایی را اعمال کرد سیاستهایی از قبیل سطح لاگ گیری، تاریخچه نگهداری لاگها، تخصیص منابع، تعیین اولویتها و….
تعیین کلاس برای یک job باید در هنگام ایجاد آن(از طریق پروسیجرcreate_job) و با کمک پارامتر job_class انجام شود که در صورت عدم تعریف ان، jobها در کلاس DEFAULT_JOB_CLASS قرار می گیرند.
برای ساخت یک job_class جدید باید از پروسیجر create_job_class استفاده کرد که پارامترهای ان در ادامه خواهند امد.
job_class_name: این پارامتر، نام job class را مشخص خواهد کرد.
resource_consumer_group: جابهای موجود در این کلاس از کدام resource consumer group استفاده می کنند. لیست consumer groupها با دستور زیر تعیین می شود:
select consumer_group from dba_rsrc_consumer_groups;
در ادامه مثالی در مورد نحوه ایجاد یک resource plan اورده شده است:
exec dbms_resource_manager.create_pending_area();
exec dbms_resource_manager.create_plan(plan => ‘PLANU’, comment => ‘plan’);
exec dbms_resource_manager.create_consumer_group ( consumer_group => ‘GROUPU’ , comment =>’consumer_group’);
exec dbms_resource_manager.create_plan_directive ( plan => ‘PLANU’,group_or_subplan =>‘GROUPU’,comment => ‘Limit CPU resource’,parallel_degree_limit_p1 => 4 );
exec dbms_resource_manager.validate_pending_area();
exec dbms_resource_manager.create_plan_directive ( plan => ‘PLANU’,group_or_subplan =>‘OTHER_GROUPS’,comment => ‘Limit CPU resource’,parallel_degree_limit_p1 => 2);
exec dbms_resource_manager.validate_pending_area();
exec dbms_resource_manager.submit_pending_area();
exec dbms_resource_manager.create_pending_area();
exec dbms_resource_manager_privs.grant_switch_consumer_group(grantee_name=>‘USEF’,consumer_group=>‘GROUPU’,grant_option=>FALSE);
exec dbms_resource_manager.set_initial_consumer_group(user => ‘USEF’,consumer_group =>‘GROUPU’);
exec dbms_resource_manager.submit_pending_area();
Service: تعیین نام سرویس که می تواند جاب مورد نظر را به instanceای به خصوص وصل کند.
logging_level: سطح لاگ گیری را مشخص می کند که می تواند مقادیر زیر را به خود بگیرد:
DBMS_SCHEDULER.LOGGING_OFF هیچ لاگی ثبت نمی شود
DBMS_SCHEDULER.LOGGING_RUNS تنها زمان استارت ثبت می شود
DBMS_SCHEDULER.LOGGING_FULL ثبت همه اطلاعات
log_history: چند روز لاگها در سیستم باقی بمانند.
برای ساخت یک job class، تنها دو پارامتر اول اجباری می باشند. مثال:
BEGIN
DBMS_SCHEDULER.create_job_class (job_class_name => ‘job_usef’,resource_consumer_group => ‘DSS_GROUP’);
END;
/
برای مشاهده لیست job classها و consumer group مربوط به انها می توان از پرس و جوی زیر استفاده کرد:
select job_class_name,resource_consumer_group from dba_scheduler_job_classes;
برای حذف یک job class هم می توان از پروسیجر drop_job_class استفاده کرد. مثال:
BEGIN
DBMS_SCHEDULER.drop_job_class(job_class_name => ‘job_usef’,force => TRUE);
end;
/
Window
Window کاربردی شبیه به schedule دارد با این تفاوت که می تواند اجرای کارها را تنها به بازه زمانی معینی محدود کند تا پس از ان بازه زمانی معین، job مورد نظر متوقف شود حتی اگر به صورت کامل اجرا نشده باشد(البته بین window و schedule تفاوتهای بسیار مهم دیگری هم وجود دارد که در ادامه به ان اشاره خواهد شد).
برای ایجاد window از پروسیجر CREATE_WINDOW استفاده می شود:
BEGIN
dbms_scheduler.create_window(
window_name => ‘EARLY_MORNING_WINDOW’,
duration => numtodsinterval(1, ‘hour’),
resource_plan => ‘DEFAULT_MAINTENANCE_PLAN’,
repeat_interval => ‘FREQ=DAILY;BYHOUR=5;BYMINUTE=0;BYSECOND=0’);
END;
نکته: مقدار پارمتر duration به اشکال مختلف قابل تعیین می باشد که برای نمونه می توان به موارد زیر اشاره کرد:
-استفاده از تابع NUMTODSINTERVAL :
NUMTODSINTERVAL(150, ‘DAY’)
NUMTODSINTERVAL(1500, ‘HOUR’)
NUMTODSINTERVAL(15000, ‘MINUTE’)
NUMTODSINTERVAL(150000, ‘SECOND’)
*استفاده از عبارت interval:
interval ‘1’ second
interval ‘1’ minute
interval ‘1’ hour
interval ‘1’ day
البته می توان از پرس و جوی زیر هم کمک گرفت:
SQL> SELECT NUMTODSINTERVAL(1, ‘MINUTE’) FROM dual;
NUMTODSINTERVAL(1,’MINUTE’)
———————————————————————
+000000000 00:01:00.000000000
-ایجاد window با کمک schedule:
BEGIN
DBMS_SCHEDULER.CREATE_WINDOW (
window_name => ‘WIN1’,
schedule_name => ‘USEF.SCHED1’,
resource_plan => ‘DEFAULT_PLAN’,
duration => interval ‘1’ minute,
comments => ‘WIN1’);
END;
/
-ایجاد job با کمک window:
begin
sys.dbms_scheduler.create_job(job_name => ‘USEF.WINJOB’,
program_name => ‘USEF.PRG3’,
schedule_name => ‘SYS.WIN1’,
job_class => ‘AUTO_TASKS_JOB_CLASS’,
enabled => false,
auto_drop => false,
comments => ”);
sys.dbms_scheduler.enable(name => ‘USEF.WINJOB’);
end;
/
برای تغییر خصوصیات فعلی یک ویندو، باید از پروسیجر SET_ATTRIBUTE استفاده کرد برای مثال، بلاک زیر مدت زمان اجرای ویندو SATURDAY_WINDOW را به 4 ساعت تغییر میدهد البته قبل از اعمال این تغییر، باید این ویندو را غیرفعال کرد و بعد از اعمال تغییرات، این ویندو را به حالت فعال دراورد:
BEGIN
dbms_scheduler.disable(name => ‘SATURDAY_WINDOW’);
dbms_scheduler.set_attribute(name => ‘SATURDAY_WINDOW’,
attribute => ‘DURATION’,
value => numtodsinterval(4, ‘hour’));
dbms_scheduler.enable(name => ‘SATURDAY_WINDOW’);
END;
-در هر زمان تنها یک ویندو می تواند باز باشد همچنین زمانی که دو ویندو بخواهند با هم اجرا شوند، مقدار پارامتر window_priority بسیار موثر خواهد بود تا کدام یک از windowها با توجه به اولویتی که دارد، به اجرا در بیاید.
SELECT window_name, resource_plan, enabled, active FROM dba_scheduler_windows;
در صورتی که دو ویندو اولویت یکسانی داشته باشند، ویندویی که درصد بیشتری از ان باقی مانده است، به اجرا در خواهد امد.همچنین اگر ویندویی در حال اجرا باشد و ویندوی جدیدی که اولویت بالاتری دارد، قصد اجرا شدن را داشته باشد، ویندوی در حال اجرا متوقف خواهد شد و جای خود را به ویندوی با اولویت بالاتر خواهد داد. -پنجره ها را می توان به صورت دستی باز کرد و یا بست. استفاده از عبارت force سبب می شود تا بدون ملاحضه اولویتها، ویندو مورد نظر باز شود همچنین می توان برای اجرای ویندوی مورد نظر، زمانی را تعیین کرد:
exec DBMS_SCHEDULER.open_window ( window_name => ‘test2’,duration=> INTERVAL ‘1’ MINUTE, force=> TRUE);
exec DBMS_SCHEDULER.close_window (window_name => ‘test2’);
-جزییات ویندوها را می توان در ویوهای DBA_SCHEDULER_WINDOW_LOG و DBA_SCHEDULER_WINDOWS مشاهده کرد.
مثال: در مثال زیر، اثر بسته شدن ویندو بر روی job روشن خواهد شد.برای این کار، ابتدا جدولی را ایجاد می کنیم:
create table usef_tbl(id number(32) primary key ,sbt_date date);
create table usef_tbl2(id number(32) primary key ,sbt_date date);
create sequence seq1;
در پروسیجر زیر، با دو وقفه، تاریخ جاری در جدول ثبت خواهد شد:
create or replace procedure usef_proc1(m number) is
begin
dbms_lock.sleep(20);
insert into usef_tbl values (seq1.nextval, sysdate);
commit;
dbms_lock.sleep(45);
insert into usef_tbl2 values (seq1.nextval, sysdate);
commit;
end;
در ادامه ویندویی ایجاد می کنیم که سه دقیقه یکبار اجرا شده و به مدت یک دقیقه به طول خواهد انجامید:
begin
sys.dbms_scheduler.create_window(window_name => ‘WM2’,
resource_plan => ‘DEFAULT_MAINTENANCE_PLAN’,
start_date => to_date(null),
repeat_interval => ‘Freq=Minutely;Interval=3’,
end_date => to_date(null),
duration => ’00 00:01:00′,
window_priority => ‘HIGH’,
comments => ”);
end;
/
حال با دستور زیر، جابی را ایجاد خواهیم کرد:
begin
sys.dbms_scheduler.create_job(job_name => ‘SYS.WMJJ’,
job_type => ‘PLSQL_BLOCK’,
job_action => ‘usef_proc1(9);’,
schedule_name => ‘SYS.WM2’,
job_class => ‘DEFAULT_JOB_CLASS’,
enabled => true,
auto_drop => false,
comments => ”);
end;
/
به صورت پیش فرض، جاب مورد نظر بعد از بسته شدن ویندو، به کار خودش ادامه خواهد داد(چون زمان اجرای این جاب از زمان اجرای ویندو بیشتر می باشد) برای متوقف کردن جاب بعد از بسته شدن ویندو، باید خصیصه stop_on_window_close را برابر با true قرار دهیم:
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(‘WMJJ’, ‘stop_on_window_close’,true );
END;
/
-هنگام باز شدن یک ویندو، resource plan ان نیز در صورت لزوم تغییر خواهد کرد:
Fri Jul 14 22:37:54 2017
Closing scheduler window
Closing Resource Manager plan via scheduler window
Clearing Resource Manager plan via parameter
Setting Resource Manager plan SCHEDULER[0x22B0]:DEFAULT_MAINTENANCE_PLAN via scheduler window
Setting Resource Manager plan DEFAULT_MAINTENANCE_PLAN via parameter
Fri Jul 14 22:37:54 2017
Starting background process VKRM
Fri Jul 14 22:37:54 2017
VKRM started with pid=34, OS id=28785
Closing scheduler window
Closing Resource Manager plan via scheduler window
Clearing Resource Manager plan via parameter
Setting Resource Manager plan SCHEDULER[0x5D10C]:PLANU via scheduler window
Setting Resource Manager plan PLANU via parameter
برای ممانعت از تغییر resource plan در زمان اجرای جاب، می توانیم از دو حربه زیر استفاده کنیم:
یک: تنظیم جبری پارامتر RESOURCE_MANAGER_PLAN به مقداری مشخص:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = ‘FORCE:mydb_plan’;
دوم:تنظیم صفت RESOURCE_PLAN به مقدار null:
execute dbms_scheduler.set_attribute(‘WEEKNIGHT_WINDOW’,’RESOURCE_PLAN’,”);
–برای بدست اوردن شکل ddl یک job، باید از پرس و جوی زیر استفاده کرد:
SELECT to_char(DBMS_METADATA.get_ddl(‘PROCOBJ’,’JOB_NAME’, ‘USEF’)) AS job_def FROM dual;
-ویوی زیر اطلاعاتی از قبیل متوسط و حداکثر را در مورد windowهای اجرا شده در بانک را به ما خواهد داد:
select c.client_name,c.status,w.window_group_name,w.next_start_date as next_start_date,extract(hour from c.mean_job_duration) * 60 + extract(minute from c.mean_job_duration) as mean_job_duration,extract(hour from c.max_duration_last_7_days) * 60 + extract(minute from c.max_duration_last_7_days) as mdl7 from dba_autotask_client c ,dba_scheduler_window_groups w where w.window_group_name = c.window_group order by 1 ;
همچنین وضعیت جاری ویندوی مورد نظر از طریق پرس و جوی زیر بدست می اید:
select l.active from dba_scheduler_windows l where l.window_name=’W1′;
window group
همانطور که مشخص شد، هر job در هر لحظه تنها می تواند از یک window استفاده کند که در این صورت محدودیتها و قوانین ان ویندو برای ان جاب اعمال خواهد شد حال در صورتی که بخواهیم یک job در هر اجرا، در یک ویندو به خصوص قرار بگیرد، می توانیم از window group استفاده کنیم که در این صورت مجموعه ای از چند window تحت یک نام در یک گروه قرار می گیرند و job موجود در این گروه، در زمانهای تعیین شده در هر یک از این ویندوها، به اجرا در خواهد امد(البته با رعایت اولویتها و محدودیتها). همچنین باید تکرار شود که در هر لحظه تنها یک ویندو اجازه باز شدن را دارد.
برای مشاهده لیست window groupها به همراه اعضای هر یک از انها، می توان از ویوی dba_scheduler_wingroup_members استفاده کرد.
Automated Maintenance Task
همانطور که می دانید، اوراکل چند مورد از وظایف dba را به صورت خودکار و معمولا در زمانی خارج از پیک کاری سیستم انجام می دهد و در صورت لزوم خروجی ای را ارائه می کند تا dba بتواند از ان خروجی بهرمند شود. از بین این کارها Automatic Segment Advisor و Automatic SQL Tuning Advisor ممکن است توصیه هایی را به dba ارائه بدهند و Automatic Optimizer Statistics Collection هم وظیفه دارد تا امارهای مربوط به اشیاها را در صورت فقدان و یا stale بودنشان، بروز کند.
نکته ای که سبب شد تا این مبحث را در این قسمت مورد بررسی قرار دهیم، ارتباط automated maintenance task با maintenance window می باشد که در ادامه چگونگی ارتباط بین انها خواهد امد.
زمانی که maintenance window به حالت open در می اید، به صورت خودکار برای هر maintenance task جابی ایجاد می شود که نام ان در زمان اجرا و با پیشوند ORA$AT مشخص می شود برای صورت مثال، در بانک ما ORA$AT_OS_OPT_SY_8 برای Optimizer Statistics و ORA$AT_SA_SPC_SY_11 برای Segment Advisor ساخته شده است. جاب ایجاد شده، بلافاصله بعد از اجرا، به صورت کامل از لیست جابها پاک خواهد شد و تنها در logها ردپایی از ان باقی خواهد ماند(ویوی dba_scheduler_job_log).
-در صورتی که maintenance window خیلی طولانی شود، به جز Automatic SQL Tuning Advisor دو task دیگر هر چهار ساعت یکبار تکرار می شود.
-برای فعال و غیرفعال کردن هر یک از این taskها، می توان از پکیج DBMS_AUTO_TASK_ADMIN استفاده کرد.
exec dbms_auto_task_admin.disable(client_name => ‘sql tuning advisor’,operation => NULL,window_name => NULL);
همچنین می توان برای یک window خاص این task را غیر فعال کرد:
exec dbms_auto_task_admin.disable(client_name => ‘sql tuning advisor’, operation => NULL, window_name => ‘MONDAY_WINDOW’);
برای مشاهده وضعیت فعلی هر کدام از این taskها، می توان از پرس و جوی زیر استفاده کرد:
select client_name, status from dba_autotask_client;
-برای تغییر زمان اجرای maintenance windowها می توان از دستورات زیر کمک گرفت:
تنظیم زمان مناسب برای WEEKNIGHT_WINDOW:
exec DBMS_SCHEDULER.disable(name=>’”SYS”.”WEEKNIGHT_WINDOW”‘);
exec dbms_scheduler.set_attribute(‘WEEKNIGHT_WINDOW’,’REPEAT_INTERVAL’,’freq=daily;byday=SUN,SAT,MON,TUE,WED,THU;byhour=20;byminute=0;bysecond=0′);
exec dbms_scheduler.set_attribute(‘WEEKNIGHT_WINDOW’,’DURATION’,’+000 08:00:00′);
exec DBMS_SCHEDULER.ENABLE(name=>’”SYS”.”WEEKNIGHT_WINDOW”‘);
تنظیم زمان مناسب برای WEEKEND_WINDOW:
exec DBMS_SCHEDULER.disable(name=>’”SYS”.”WEEKEND_WINDOW”‘);
exec dbms_scheduler.set_attribute(‘WEEKEND_WINDOW’,’REPEAT_INTERVAL’,’freq=daily;byday=FRI;byhour=02;byminute=0;bysecond=0′);
exec dbms_scheduler.set_attribute(‘WEEKEND_WINDOW’,’DURATION’,’+000 23:00:00′);
exec DBMS_SCHEDULER.ENABLE(name=>’”SYS”.”WEEKEND_WINDOW”‘);
برای مشاهده وضعیت فعلی maintenance windowها می توان از پرس و جوی زیر استفاده کرد:
select window_name, repeat_interval, duration,l.enabled,active from dba_scheduler_windows l;
نکاتی در مورد SCHEDULER:
نکته 1: اطلاعات scheduler در جدول SCHEDULER$_JOB ذخیره می شود.
نکته 2: زمانی که job به طور مستقیم توسط کاربر اجرا می شود، در لیست jobهای در حال اجرا قابل مشاهده نیست(یعنی نمی توان آن را در dba_scheduler_running_jobs مشاهده کرد)
نکته 3: به صورت پیش فرض، لاگها به مدت سی روز حفظ می شوند و پس از آن پاک خواهند شد این مقدار از طریق ویوی dba_scheduler_global_attribute قابل مشاهده می باشد و می توان این مقدار را به صورت زیر تغییر داد:
begin
DBMS_SCHEDULER.SET_SCHEDULER_ATTRIBUTE(‘log_history’,’111′);
end;
حذف لاگها به صورت دستی هم امکان پذیر می باشد:
begin DBMS_SCHEDULER.PURGE_LOG(); end;
همچنین می توان لاگها را به صورت بازه ای حذف کرد:
begin DBMS_SCHEDULER.PURGE_LOG(log_history => 3, which_log => ‘JOB_LOG’); end;
نکته 4: تعیین اولویت هم برای jobها ممکن می باشد که در این صورت می توان به یک job، اولویتی بین عدد یک تا پنج داده شود که عدد یک، بالاترین اولویت را دارد:
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE (
name => ‘J1’,
attribute => ‘job_priority’,
value => 1);
END;
/
نکته 5: تعیین و تغییر timezone پیش فرض برای dbms_scheduler:
SELECT SYSTIMESTAMP FROM dual;
SELECT dbms_scheduler.stime FROM dual ;
select current_date, sysdate,dbtimezone,sessiontimezone from dual;
exec dbms_scheduler.set_scheduler_attribute (‘DEFAULT_TIMEZONE’, ‘Asia/Calcutta’);
مقدار جاری timezone را می توان در ویوی dba_scheduler_global_attribute مشاهده کرد.
نکته 6: در نسخه 10gR1 برای ایجاد external job، تنها داشتن مجوز create job کافی بود ولی در نسخه 11g، باید مجوز دیگری به نام CREATE EXTERNAL JOB را هم در اختیار داشت.همچنین با مجوز create any job و نقش SCHEDULER_ADMIN هم می توان ایجاد و مدیریت جابها را انجام داد.
جدول زیر به صورت دقیق تر در مورد مجوزها اطلاعاتی را ارائه می کند.
Task | Privilege Needed |
Create a job | CREATE JOB or CREATE ANY JOB |
Alter a job | ALTER or CREATE ANY JOB or be the owner |
Run a job | ALTER or CREATE ANY JOB or be the owner |
Copy a job | ALTER or CREATE ANY JOB or be the owner |
Drop a job | ALTER or CREATE ANY JOB or be the owner |
Stop a job | ALTER or CREATE ANY JOB or be the owner |
Disable a job | ALTER or CREATE ANY JOB or be the owner |
Enable a job | ALTER or CREATE ANY JOB or be the owner |
Create a program | CREATE JOB or CREATE ANY JOB |
Create a schedule | CREATE JOB or CREATE ANY JOB |
Create a job class | MANAGE SCHEDULER |
Create a window | MANAGE SCHEDULER |
Privilege Needed | MANAGE SCHEDULER |
از لحاط امنیتی توصیه می شود تا مجوز create any job به هر کسی داده نشود چون به واسطه این مجوز، کاربر می تواند برای کاربران دیگر هم جاب تعریف کند.
نکته 7: در صورتی که پارامتر JOB_QUEUE_PROCESSES برابر با صفر تنظیم شده باشد، هر دو نوع از jobها غیرفعال خواهند شد(dbms_job و dbms_schedular).
البته تنظیم این پارامتر به مقدار صفر، سبب توقف jobی که در حال اجرا می باشد نخواهد شد.
نکته8: در صورتی که خصوصیت MAX_JOB_SLAVE_PROCESSES به عدد مشخصی تنظیم شده باشد، بیش از ان تعداد، امکان اجرای job همزمان وجود نخواهد داشت(از طریق dbms_scheduler). مقدار پیش فرض این صفت، برابر با null می باشد که محدودیتی را ایجاد نخواهد کرد:
select value from dba_scheduler_global_attribute where attribute_name = ‘MAX_JOB_SLAVE_PROCESSES’;
برای تغییر مقدار این صفت به null باید:
SQL> exec dbms_scheduler.set_scheduler_attribute(‘max_job_slave_processes’,null);
نکته 9: در صورتی که خصیصه SCHEDULER_DISABLED در ویوی dba_scheduler_global_attribute برابر با true باشد، در این صورت جابهای تعریف شده توسط dbms_scheduler ، قابل اجرا نخواهند بود. برای برگرداندن ابن مقدار باید:
exec dbms_scheduler.set_scheduler_attribute(‘scheduler_disabled’,’false’);
نکته 10: یکی از دلایل عدم اجرای dbms_scheduler می تواند بخاطر عدم استارت سرویسی که در job_class به آن اشاره شده است، برگردد. در این صورت باید سرویس مربوطه را با استفاده از دستور dbms_service.start_service و یا srvctl به حالت اجرا دراورد.
نکته 11: از دیگر دلایل احتمالی عدم اجرای dbms_scheduler، می توان به محدودیت منابع تعریف شده در resource plan اشاره کرد.
نکته 12: در صورتی که در فیلد next_run_date مربوط به ویوی dba_scheduler_jobs، به timezone به صورت عددی(+04:30) اشاره شود(به جای نمایش نام timezone مثل US/PACIFIC)، ممکن است daylight saving در نظر گرفته نشود و جاب مورد نظر با یک ساعت عقب و یا جلو اجرا شود.
نکته 13: برای راه اندازی مجدد scheduler می توان دستورات زیر را اجرا کرد:
exec dbms_scheduler.set_scheduler_attribute(‘SCHEDULER_DISABLED’, ‘TRUE’);
alter system set job_queue_processes=0;
exec dbms_ijob.set_enabled(FALSE);
alter system flush shared_pool;
alter system flush shared_pool;
exec dbms_ijob.set_enabled(TRUE);
alter system set job_queue_processes=99;
exec dbms_scheduler.set_scheduler_attribute(‘SCHEDULER_DISABLED’, ‘FALSE’);
در این صورت، پروسس CJQ0 راه اندازی مجدد خواهد شد:
2017-07-02T16:09:52.058254+04:30
Stopping background process CJQ0
2017-07-02T16:09:52.073575+04:30
ALTER SYSTEM SET job_queue_processes=0 SCOPE=BOTH;
2017-07-02T16:09:53.769322+04:30
Starting background process CJQ0
2017-07-02T16:09:53.827848+04:30
ALTER SYSTEM SET job_queue_processes=99 SCOPE=BOTH;
2017-07-02T16:09:53.830816+04:30
CJQ0 started with pid=109, OS id=26481
2017-07-02T16:10:01.822576+04:30
Setting Resource Manager plan SCHEDULER[0x3009]:DEFAULT_MAINTENANCE_PLAN via scheduler window
Setting Resource Manager plan DEFAULT_MAINTENANCE_PLAN via parameter
نکته 14: با کمک پرس و جوی زیر، می توان اسکریپت لازم را برای تبدیل جابهای از نوع dbms_job به حالت scheduler را بدست اورد:
select ‘dbms_scheduler.create_job( ‘ || chr(13)|| ‘ job_name=>”’ || substr(upper(translate(what,’.(),;’,’_’)),1,26) ||’_JOB’ || ”’, ‘ || chr(13)|| ‘ job_type => ”PLSQL_BLOCK”,’ || chr(13)|| ‘ job_action=> ”begin ‘ || chr(13) || what || chr(13) || ‘end; ”, ‘ || chr(13)|| ‘ start_date => to_timestamp(”’ || to_char(next_date,’mm/dd/yyyy hh24:mi:ss’) || ”’, ”mm/dd/yyyy hh24:mi:ss”), ‘ || chr(13)|| DECODE (interval,’null’,NULL, ‘ repeat_interval => ”’ || interval || ”’, ‘ || chr(13) )|| ‘ enabled => true, auto_drop=> false, ‘ || chr(13)|| ‘ comments => ”Converted from job ‘ || job || ”” || chr(13)|| ‘);’ || chr(13) from user_jobs where broken = ‘N’;
نکته 15: مقدار پارامتر repeat_interval به طریقهای مختلفی قابل تعیین می باشد که در جدول زیر، مثالهای در این مورد اورده شده است.
Comment (1)