2017-05-12 6 views
1
DBMS_SCHEDULER.CREATE_JOB (
    job_name => 'MYJOB', 
    job_type => 'PLSQL_BLOCK', 
    job_action => <see below> 
); 

DBMS_SCHEDULER.ENABLE (
    name => 'MYJOB' 
); 

-- pl/SQL block for the job: 

BEGIN 
    -- 1 
    UPDATE ... 
    COMMIT; 

    FOR x IN (SELECT ... 
    LOOP 
     -- 2 
     UPDATE ... 
     COMMIT; 
    END LOOP; 

    -- 3 
    UPDATE ... 
    COMMIT; 
END 

私は、PL/SQL内の特別な時点でPL/SQLブロックを終了するためのスケジューラで、特別なルールがあるストップスケジューラ求人 - PL/SQLブロック内の出口点

DBMS_SCHEDULER.STOP_JOB (
    job_name => 'MYJOB', 
    force => FALSE 
); 

を実行するとブロック?上記の例では、ポイント "3"のDMLが実行されない可能性がありますか?

+0

終了点は最後の行の後にあります。 –

+0

dbms_schedulerのジョブが作成され有効化され、実行されました。 Pl/SQLブロックがまだ実行中の場合、ジョブを停止することができます。それ以外の場合は、終了します。 stop_jobプロシージャの強制オプションを確認します。これは、実際にジョブをある種「殺す」特権を必要とするためです。これのデフォルトはforce => falseで、これは割り込みメカニズムを使用します。 – g00dy

+1

@a_horse_with_no_name - 私はToruがstop_jobを発行すると、コードが実際にどこから終了するのか知りたいと思うと思います。これは強制オプションとともに使用される場合、スレーブプロセスを強制終了するか、正常に停止します。 – g00dy

答えて

3

DBMS_SCHEDULER.STOP_JOB()forceをfalseに設定しているとします。ドキュメントによると、これは「割り込み機構を使用してジョブを正常に停止する」ことを意味します。この「割り込みメカニズム」に関する細部はなく、単にウェブサイト上のサイトは、それ以上の洞察を必要とせずに文書を復活させるだけです。

何が起こるか見てみましょう。ここにあなたのことを模倣する手順があります。それが完了すると、T42には32のレコードがあります。

create or replace procedure p_job_tst is 
    n simple_integer := 1; 
begin 
    delete from t42; 
    insert into t42 (stage, id) values (1, n); 
    commit; 
    for i in 1..30 loop 
     n := n+1; 
     insert into t42 (stage, id) values (2, n); 
     commit; 
     dbms_lock.sleep(2); 
    end loop; 
    n := n+1; 
    insert into t42 (stage, id) values (3, n); 
    commit; 
end; 
/

dbms_lock.sleep()への呼び出しは、それが、私たちはタイピングで超高速になることなく、半ば実行中のジョブを停止することができた、分実行します。ここでの仕事は次のとおりです。

SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1'; 

JOB_NAME      STATE   RUN_COUNT 
------------------------------ --------------- ---------- 
MY_JOB1      SCHEDULED    2 

SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1'; 

JOB_NAME      STATE   RUN_COUNT 
------------------------------ --------------- ---------- 
MY_JOB1      RUNNING     2 

SQL> exec sys.dbms_scheduler.STOP_JOB(job_name=>'apc.my_job1', force=>false); 

PL/SQL procedure successfully completed. 

SQL> select job_name, state, run_count from dba_scheduler_jobs where job_name = 'MY_JOB1'; 

JOB_NAME      STATE   RUN_COUNT 
------------------------------ --------------- ---------- 
MY_JOB1      SCHEDULED    3 

SQL> 

私はT42が10件のレコードを持っていた仕事を停止する前に:

BEGIN 
    DBMS_SCHEDULER.CREATE_JOB (
     job_name    => 'apc.my_job1', 
     job_type    => 'PLSQL_BLOCK', 
     job_action   => 'BEGIN p_job_tst; END;', 
     start_date   => systimestamp + interval '10' second, 
     repeat_interval  => 'FREQ=MINUTELY;INTERVAL=3', 
     enabled    => TRUE, 
     comments    => 'StackOverflow Test'); 
END; 
/

は、ジョブを開始しました、それが実行しているまでのは、それを停止し、待機してみましょう。 T42の現在の内容は?

SQL> r 
    1* select * from t42 order by stage, id 

     ID  STAGE 
---------- ---------- 
     1   1 
     2   2 
     3   2 
     4   2 
     5   2 
     6   2 
     7   2 
     8   2 
     9   2 
     10   2 
     11   2 

     ID  STAGE 
---------- ---------- 
     12   2 

12 rows selected. 

SQL> 

したがって、ジョブは正常に停止しましたが、手順の最後には停止しませんでした。これは、割り込みメカニズムが、ロックや長時間実行されているプロセスのないきれいなブレークポイントを探すかのようです。あなたのコードと同じように、私のコードにはこのようなブレークポイントがたくさんあります。各commitはトランザクションを終了し、ロックを解放します。

あなたの仕事を「優雅に」止めるのは簡単だと思うので、スケジューラーの視点からは良いです。もちろん、アプリケーションの観点からは完全な悪夢です。その仕事は、で不明な状態にあります。作業の一部は完了し、コミットされ、一部は失われてしまいます。どのくらいのものがどれくらいのものかを判断する簡単な方法はなく、その間にデータベースが矛盾した状態になる可能性があります。

commitステートメントの発行に関連するベストプラクティスがあります。単位作業の最後にcommitを1回入力します。バックグラウンドジョブはUnit Of Workですので、終了する直前にcommitという文が1つ必要です(ブロックには例外ハンドラセクションがないと仮定します)。

+1

していただきありがとうございます。 – Toru

0

個人的には、ループ内での更新があるかどうかを確認する1度に1度=遅い]を、セットベースの更新であるように再コーディングすることができる。結局のところ、Oracle RDBMSは非常に効率的なセット処理エンジンとして設計されています。一度に1行ずつ実行されるソリューションは、ほとんど常にセットベースのソリューションを実行し、スケーラブルではありません。