[Oracle10G新特性]_19.調度程序
?
??? 這個屬性還真的是不錯,之前沒有注意過。特別是關于執行操作系統程序和時間定義語法的更改,非常不錯。之前想要在一天的某2個時間執行,都需要定義兩個job才可以,原來確實是可以通過decode函數來達到這個目的的,不過知道dbms_scheduler包的功能之后,就更加簡單了??傊@個又是一個10g的改進之處,非常不錯。考慮一下直接應用。
?
-----------------------------------------------------------------------------
?
調度程序
?
您是否厭倦了在 dbms_job 中手工管理時間間隔的繁瑣,需要數據庫內部有個新調度系統? 讓我們就著眼于數據庫本身來解決這個問題。
?
??? 你們中的一部分人可能廣泛使用 dbms_job 程序包來將數據庫作業提交到后臺運行,控制運行的時間或時間間隔,報告故障等等。 然而,我感覺你們中的大部分人不會這么做。
??? 這個程序包存在的問題是它只能夠處理 PL/SQL 代碼段 — 僅能處理匿名程序塊和存儲程序單元。 它不能在數據庫外部處理操作系統命令文件或可執行文件中的任何東西。 為此,您將不得不求助于操作系統調度實用工具(如 Unix 中的 cron 或 Windows 中的 AT 命令)。 或者,您可以使用甚至可能通過提供圖形用戶界面來擴展這種功能的第三方工具。
?
??? 雖然如此,dbms_job 有一個超過這些替代方法的獨特優點: 它只有在數據庫啟動并運行時才有效。 如果數據庫關閉,則作業不會運行。 數據庫外部的工具必須人工檢查數據庫是否啟動 — 而這可能很困難。 另一個優點是 dbms_job 在數據庫內部,因此您可以通過數據庫訪問實用工具(如 SQL*Plus)來訪問它。
?
??? Oracle 數據庫 10g 調度程序特性提供了各方面的好處: 它是直接在數據庫內部的一個作業調度實用程序,強大到足夠處理所有類型的作業,而不只是 PL/SQL 代碼段。 最好的一點是,它是數據庫自帶的,無需任何額外的成本。 在這一部分中,我們將看看它是如何工作的。
?
?
將作業與程序連接
?
??? 也許最好通過一個例子來介紹這個概念。 假定您創建了一個 shell 腳本,以將存檔的日志文件轉移到一個不同的文件系統中,如下:
?
/home/arup/dbtools/move_arcs.sh
?
??? 首先,您需要使數據庫知道這個腳本是一個要在作業中使用的程序。 要創建這個程序,您必須擁有 CREATE JOB 權限。
?
begin
??? dbms_scheduler.create_program
??? (
?????? program_name?? => 'MOVE_ARCS',
?????? program_type?? => 'EXECUTABLE',
?????? program_action => '/home/arup/dbtools/move_arcs.sh',
?????? enabled??????? => TRUE,
?????? comments?????? => 'Moving Archived Logs to Staging Directory'
??? );
end;
/
?
??? 這里您創建了一個命名程序單元,將其指定為可執行文件。注意這個程序單元叫什么。
?
??? 接下來,您將創建一個每 30 分鐘運行一次的命名計劃,該計劃的名稱為 EVERY_30_MINS。 您將使用以下命令來完成這一操作:
?
begin
??? dbms_scheduler.create_schedule
??? (
?????? schedule_name?? => 'EVERY_30_MINS',
?????? repeat_interval => 'FREQ=MINUTELY; INTERVAL=30',
?????? comments??????? => 'Every 30-mins'
??? );
end;
/
?
??? 現在創建了程序和計劃,接著您將把程序與計劃連接來創建作業。
?
begin
?? dbms_scheduler.create_job
?? (
????? job_name????? => 'ARC_MOVE',
????? program_name? => 'MOVE_ARCS',
????? schedule_name => 'EVERY_30_MINS',
????? comments????? => 'Move Archived Logs to a Different Directory',
????? enabled?????? => TRUE
?? );
end;
/
?
??? 這將創建一個每 30 分鐘運行一次的作業,該作業執行 shell 腳本 move_arcs.sh。它將由數據庫內部的調度程序特性來處理 — 無需 cron 或 AT 實用工具。
?
?
創建沒有程序的作業
?
??? 在上述情況下,您創建了一個程序來引用一個操作系統實用工具或程序,并創建了一個計劃來指定運行的次數,最后將這兩者連接起來創建作業。 不過,不需要從程序中創建作業;也可以獨立地定義它們。 例如,您可以創建上述作業,而無需首先創建一個程序。
?
begin
?? dbms_scheduler.create_job
?? (
????? job_name????? => 'ARC_MOVE_2',
????? schedule_name => 'EVERY_30_MINS',
????? job_type????? => 'EXECUTABLE',
????? job_action??? => '/home/arup/dbtools/move_arcs.sh',
????? enabled?????? => true,
????? comments????? => 'Move Archived Logs to a Different Directory'
?? );
end;
/
?
??? 這里直接指定 OS 可執行文件,而無需首先將其創建為一個程序。 同樣,您可以創建一個作業,而無需一個命名的計劃。
?
begin
?? dbms_scheduler.create_job
?? (
????? job_name??????? => 'ARC_MOVE_3',
????? job_type??????? => 'EXECUTABLE',
????? job_action????? => '/home/arup/dbtools/move_arcs.sh',
????? repeat_interval => 'FREQ=MINUTELY; INTERVAL=30',
????? enabled???????? => true,
????? comments??????? => 'Move Archived Logs to a Different Directory'
?? );
end;
/
?
??? Scheduler 超過 dbms_job 的一個優點從我們最初的例子中可以很清楚地看出來: 能夠調用 OS 實用工具和程序,而不只是 PL/SQL 程序單元。 這一能力使它成為管理 Oracle 數據庫和相關作業的最全面的作業管理工具。
?
??? 不過,您可能已經注意到了另一個同樣重要的優點: 能夠以自然語言定義時間間隔。 注意在上面的例子中,我們要我們的計劃每 30 分鐘運行一次,因此通過一個簡單的類似英語的表達式(而不是 PL/SQL)定義了 REPEAT_INTERVAL 參數:
?
'FREQ=MINUTELY; INTERVAL=30'
?
??? 一個更復雜的例子甚至可以更好地幫助說明這一優點。 假定您的生產應用程序在上午 7:00 和下午 3:00 變得最活躍,為了收集系統統計數據,您想從星期一到星期五僅在上午 7:00 和下午 3:00 運行 Statspack。 如果您使用 DBMS_JOB.SUBMIT 來創建一個作業,那么 NEXT_DATE 參數將看起來像這樣:
?
DECODE
(
?? SIGN
?? (
????? 15 - TO_CHAR(SYSDATE,'HH24')
?? ),
?? 1,
????? TRUNC(SYSDATE)+15/24,
?? TRUNC
?? (
????? SYSDATE +
????? DECODE
????? (
????????? TO_CHAR(SYSDATE,'D'), 6, 3, 1
????? )
??? )
??? +7/24
)
?
??? 這種代碼容易理解嗎?實際上不容易。
?
??? 現在讓我們看看 DBMS_SCHEDULER 中的等價的作業。 REPEAT_INTERVAL 參數將像下面這么簡單:
'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=7,15'
?
??? 此外,這個參數值可以接收各種時間間隔,它們中的一些非常強大。 下面是更多的一些例子:
?
????? ● 每月的最后一個星期天:
????? FREQ=MONTHLY; BYDAY=-1SUN
?
????? ● 每月的第三個星期五:
????? FREQ=MONTHLY; BYDAY=3FRI
?
????? ● 從每月底算起(而不是從每月初算起)的第二個星期五:
????? FREQ=MONTHLY; BYDAY=-2FRI
?
??? 數字前面的負號指示從月底算起,而不是從月初算起。
?
??? 如果您想要驗證時間間隔設置是否正確,那應該怎么辦? 看看從日歷字符串中構造的各個日期不是很好嗎? 好的,您可以使用 EVALUATE_CALENDAR_STRING 過程來預覽接下來的日期的計算。 利用第一個例子 — 從星期一到星期五每天在上午 7:00 和下午 3:00 運行 Statspack — 您可以按如下方式檢查您的時間間隔字符串的準確性:
?
set serveroutput on size 999999
?
declare
?? L_start_date??? TIMESTAMP;
?? l_next_date???? TIMESTAMP;
?? l_return_date?? TIMESTAMP;
begin
?? l_start_date := trunc(SYSTIMESTAMP);
?? l_return_date := l_start_date;
?? for ctr in 1..10 loop
????? dbms_scheduler.evaluate_calendar_string(
??????? 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=7,15',
???????? l_start_date, l_return_date, l_next_date
????? );
????? dbms_output.put_line('Next Run on: ' ||
????????? to_char(l_next_date,'mm/dd/yyyy hh24:mi:ss')
????? );
????? l_return_date := l_next_date;
end loop;
end;
/
?
??? 輸出結果如下:
?
Next Run on: 03/22/2004 07:00:00
Next Run on: 03/22/2004 15:00:00
Next Run on: 03/23/2004 07:00:00
Next Run on: 03/23/2004 15:00:00
Next Run on: 03/24/2004 07:00:00
Next Run on: 03/24/2004 15:00:00
Next Run on: 03/25/2004 07:00:00
Next Run on: 03/25/2004 15:00:00
Next Run on: 03/26/2004 07:00:00
Next Run on: 03/26/2004 15:00:00
?
??? 這確認您的設置是正確的。
?
?
類、計劃和窗口
?
??? 一個稱職的好的作業調度系統必須支持為作業安排優先級的能力。 例如,統計數據收集作業突然進入 OLTP 工作負載窗口,從而可能影響那里的性能。 為了確保統計數據收集作業不消耗資源從而影響 OLTP,您可以使用作業類、資源計劃和調度程序窗口。
???
??? 例如,當定義一個作業時,您可以使之屬于一個作業類,作業類映射到一個資源使用組上,以進行資源分配。 為此,首先您需要定義一個名稱為(比如說) OLTP_GROUP 的資源使用組。
?
begin
?? dbms_resource_manager.clear_pending_area();
?? dbms_resource_manager.create_pending_area();
?? dbms_resource_manager.create_consumer_group (
?????? consumer_group => 'oltp_group',??
?????? comment => 'OLTP Activity Group'
?? );
?? dbms_resource_manager.submit_pending_area();
end;
/
?
??? 接下來,您需要創建一個資源計劃。
?
begin
?? dbms_resource_manager.clear_pending_area();
?? dbms_resource_manager.create_pending_area();
?? dbms_resource_manager.create_plan
????? ('OLTP_PLAN', 'OLTP Database Activity Plan');
?? dbms_resource_manager.create_plan_directive(
????? plan => 'OLTP_PLAN',
????? group_or_subplan => 'OLTP_GROUP',
????? comment => 'This is the OLTP Plan',
????? cpu_p1 => 80, cpu_p2 => NULL, cpu_p3 => NULL, cpu_p4 => NULL,
????? cpu_p5 => NULL, cpu_p6 => NULL, cpu_p7 => NULL, cpu_p8 => NULL,
????? parallel_degree_limit_p1 => 4,
????? active_sess_pool_p1 => NULL,
????? queueing_p1 => NULL,
????? switch_group => 'OTHER_GROUPS',
????? switch_time => 10,
????? switch_estimate => true,
????? max_est_exec_time => 10,
????? undo_pool => 500,
????? max_idle_time => NULL,
????? max_idle_blocker_time => NULL,
????? switch_time_in_call => NULL
?? );
?? dbms_resource_manager.create_plan_directive(
????? plan => 'OLTP_PLAN',
????? group_or_subplan => 'OTHER_GROUPS',
????? comment => NULL,
????? cpu_p1 => 20, cpu_p2 => NULL, cpu_p3 => NULL, cpu_p4 => NULL,
????? cpu_p5 => NULL, cpu_p6 => NULL, cpu_p7 => NULL, cpu_p8 => NULL,
????? parallel_degree_limit_p1 => 0,
????? active_sess_pool_p1 => 0,
????? queueing_p1 => 0,
????? switch_group => NULL,
????? switch_time => NULL,
????? switch_estimate => false,
????? max_est_exec_time => 0,
????? undo_pool => 10,
????? max_idle_time => NULL,
????? max_idle_blocker_time => NULL,
????? switch_time_in_call => NULL
?? );
?? dbms_resource_manager.submit_pending_area();
end;
/
?
??? 最后,您利用之前創建的資源使用組來創建一個作業類。
?
begin
?? dbms_scheduler.create_job_class(
????? job_class_name => 'OLTP_JOBS',
????? logging_level => DBMS_SCHEDULER.LOGGING_FULL,
????? log_history => 45,
????? resource_consumer_group => 'OLTP_GROUP',
????? comments => 'OLTP Related Jobs'
?? );
end;
/
?
??? 讓我們看看這個調用中的各個參數。 LOGGING_LEVEL 參數設置為作業類跟蹤多少日志數據。 設置 LOGGING_FULL 指示這個類中的作業上的所有活動 — 創建、刪除、運行、更替等等 — 都將被記錄在日志中。 這些日志可以從 DBA_SCHEDULER_JOB_LOG 視圖中看到,并保留 45 天(在 LOG_HISTORY 參數中指定,默認值是 30 天)。 還指定了與這個類相連的資源使用組。 這些作業類可以從 DBA_SCHEDULER_JOB_CLASSES 視圖中看到。
?
??? 當您創建一個作業時,您可以隨意地將其與一個類關聯。 例如,當創建 COLLECT_STATS 時,對于一個通過執行一個存儲過程來收集優化程序統計數據的作業 collect_opt_stats(),您可能已經指定了:
?
begin
?? dbms_scheduler.create_job
?? (
????? job_name??????? => 'COLLECT_STATS',
????? job_type??????? => 'STORED_PROCEDURE',
????? job_action????? => 'collect_opt_stats',
????? job_class?????? => 'OLTP_JOBS',
????? repeat_interval => 'FREQ=WEEKLY; INTERVAL=1',
????? enabled???????? => true,
????? comments??????? => 'Collect Optimizer Stats'
?? );
end;
/
?
??? 這些命令將把新創建的作業放在 OLTP_JOBS 類中,然后后者由資源計劃 OLTP_GROUP 來管理,該資源計劃將限制分配多少 CPU 給過程、在它被切換到一個不同的組之前的最大運行數、要切換到的組等等。 在這個類中定義的任意作業都將由相同的資源計劃指令來管理。 這一功能對于防止不同類型的作業過度占用系統資源特別有用。
?
??? 調度程序窗口是擁有一個相關的資源計劃的時間幀,它用于激活該計劃 — 從而在一個時間幀上支持作業的不同優先級。 例如,一些作業(如更新數據庫以支持實時決策的批量程序)在白天需要高優先級但在晚上變為低優先級(反之亦然)。 您可以通過定義不同的資源計劃,然后使用調度程序窗口激活它們來實施這種調度。
?
?
監視
?
??? 在一個作業啟動之后,您可以從 DBA_SCHEDULER_JOB_LOG 視圖中監視它的狀態,其中 STATUS 列顯示了作業的當前狀態。 如果它顯示 FAILED,那么您可以進一步向下查看,以從 DBA_SCHEDULER_JOB_RUN_DETAILS 視圖中找出原因。
?
?
管理
?
??? 迄今為止,我們已經討論了如何創建幾種類型的對象: 程序、計劃、作業類和作業。 如果您想修改它們中的一些,以調整適應不斷變化的需求,那該怎么辦? 好的,您可以通過 DBMS_SCHEDULER 程序包中提供的 API 來實現這一目的。
?
??? 從企業管理器 10g 主頁的 Database 標簽中,單擊 Administration 鏈接。 這將顯示 Administration 屏幕(如圖 1 所示)。所有與調度程序相關的任務都可以在右下角的 "Scheduler" 標題下找到(顯示在圖中的一個紅色橢圓中)。
?
?
圖 1: Administration 頁面
?
??? 所有與調度程序相關的任務(如創建、刪除和維護作業)都能夠通過該頁面中的超鏈接任務輕松完成。 讓我們看看這些任務中的一部分。 我們在早些時候創建了所有這些任務,因此單擊 Jobs 標簽將顯示一個類似于圖 2 的屏幕。
?
?
圖 2: 計劃作業
?
??? 單擊 COLLECT_STATS 作業允許您修改它的屬性。 當您單擊 "Job Name" 時,將出現圖 3 中顯示的屏幕。
?
?
圖 3: 作業參數
?
??? 正如您所看到的,您可以通過單擊相應的標簽來修改作業的參數以及計劃和選項。 在完成所有的修改之后,您可以按下 "Apply" 鍵,使修改變為永久性的。 在這么做之前,您可能想單擊標記為 "Show SQL" 的按鈕,它顯示將執行的確切的 SQL 語句 — 即使原因只是要查看調用了哪些 API,從而使您能夠了解幕后的工作。 您還可以將 SQL 存儲在一個腳本中,并在以后執行它,或者將它存儲為一個模板,以便將來使用。
?
?
結論
?
??? Oracle 數據庫 10g 中的調度程序是從原來的 dbms_job 接口實現的巨大的飛躍。
?
?
?
?
?
?
?
?