2

(理論的な理由から) 5 分間という長時間実行されるパッケージのプロシージャを呼び出す更新後の行レベル トリガーがあると仮定します。最初の実行がまだ実行されている間に、このトリガーを 2 回目に実行する方法はありますか?

セッション A からトリガーを 1 回トリガーし、すぐにもう一度トリガーするとどうなりますか?

セッション A からトリガーを 1 回トリガーし、すぐにセッション B からもう一度トリガーするとどうなりますか?

それらは並行して実行されますか、それとも最初の実行が完了するまで 5 分待つだけですか?

これらの質問に関して、行レベルのトリガーまたはステートメントレベルのトリガーについて話しても、違いはありますか?

ありがとう。

4

4 に答える 4

3

これは、手順で開始時刻と終了時刻を表示するなど、かなり簡単にテストできます。(デモンストレーションするサンプル コードを以下に示します)。セッション A 内で、次の場合:

update <table> set ...;
update <table> set ...;

...トリガーは、そのステートメントの一部としての最初の更新に対して、影響を受ける行ごとに順番に起動します。その後、2 番目の更新が実行され、影響を受ける行ごとにトリガーが再び順番に起動されます。プロシージャは常に 1 回だけ実行されますが、更新を行う可能性があり、それぞれの影響を受ける行が多くなります。

ステートメント レベルのトリガーに変更しても、プロシージャは常に 1 回しか実行されませんが、更新が複数の行に影響する場合は、更新された行ごとに 1 回ではなく、更新ごとに 1 回、全体として実行される回数が少なくなります。

ただし、セッション B から 2 番目の更新を同時に実行した場合 (そしてテーブル内の異なる行に触れている場合)、最初のセッションの影響を受けないため、プロシージャが同時に 2 回実行されますそれが行レベルのトリガーかステートメント レベルのトリガーかは問題ではありません。各セッションで 1 回実行されます。

プロシージャが異なるセッションから 2 回実行されるのを避けたい場合は、プロシージャの開始時に別のテーブルの制御フラグを更新するなど、ある種のロック メカニズムを実装する必要があります。そのセッションがコミットまたはロールバックすると解放され、他のセッションは続行して独自のロックを取得します。

ただし、それほど時間がかかる手順を呼び出すトリガーを持つことは、非常に間違っているようです。ビジネスとアプリケーションのロジックが間違った場所にあるようです...


セッション A で 2 回実行するためのデモ コード:

create table t42 (id number);

insert into t42 values (1);
insert into t42 values (2);

create package p42 as
  procedure busy;
end p42;
/

create package body p42 as
  procedure busy is
    x number;
  begin
    dbms_output.put_line('Started  ' || systimestamp);
    for i in 1..200000 loop -- takes about 4s on my system
      select 1 into x from dual;
    end loop;
    dbms_output.put_line('Finished ' || systimestamp);
  end busy;
end p42;
/

create trigger trig42
after update on t42
for each row
begin
  p42.busy;
end;
/

次に、2 つの更新を実行します。

update t42 set id = id + 1;
update t42 set id = id + 1;

出力を取得します:

2 rows updated.
Started  08-AUG-13 18.17.49.184770000 +01:00
Finished 08-AUG-13 18.17.53.041916000 +01:00
Started  08-AUG-13 18.17.53.042109000 +01:00
Finished 08-AUG-13 18.17.56.841698000 +01:00

2 rows updated.
Started  08-AUG-13 18.17.57.027777000 +01:00
Finished 08-AUG-13 18.18.01.172613000 +01:00
Started  08-AUG-13 18.18.01.172730000 +01:00
Finished 08-AUG-13 18.18.04.963734000 +01:00

プロシージャは合計 4 回実行され、タイムスタンプはプロシージャの実行がシリアルであることを示しています。セッション A とセッション B で ID 固有の更新を同時に実行すると、セッション A には次のように表示されます。

update t42 set id = id + 1 where id = 1;
1 rows updated.
Started  08-AUG-13 18.21.09.098922000 +01:00
Finished 08-AUG-13 18.21.16.355744000 +01:00

セッション B には次のように表示されます。

update t42 set id = id + 1 where id = 2;
Started  08-AUG-13 18.21.09.500643000 +01:00
Finished 08-AUG-13 18.21.16.204506000 +01:00
1 row updated.

ご覧のとおり、タイムスタンプが重複しているため、プロシージャは同時に 2 回実行されています。

非常に単純なロック メカニズムを追加します。

create table t43 (id number);
insert into t43 values(null);

create package body p42 as
  procedure busy is
    x number;
  begin
    update t43 set id = 1;
    dbms_output.put_line('Started  ' || systimestamp);
  ...
end p42;

次に、セッション A で:

update t42 set id = id + 1 where id = 1;
1 rows updated.
Started  08-AUG-13 18.22.35.058741000 +01:00
Finished 08-AUG-13 18.22.39.288557000 +01:00
rollback;

同時にセッション B:

update t42 set id = id + 1 where id = 2;
Started  08-AUG-13 18.22.40.385602000 +01:00
Finished 08-AUG-13 18.22.43.995601000 +01:00
1 row updated.
rollback;

これで、2 つのセッションからの呼び出しもシリアライズされます。セッション B の更新のプロシージャ コールは、セッション A がロールバックされるまで開始できないため、セッション A が複数のアクションを実行した場合、より長くブロックされる可能性があります。

于 2013-08-08T16:50:21.053 に答える
3

トリガーは条件が発生するとすぐに実行されます。したがって、セッション A で 2 回トリガーされた場合、トリガーは最初の発生で 1 回実行され、2 回目の発生で再度実行されるため、実行は連続して実行され、合計 10 回かかります。分。トリガーがセッション A から 1 回起動され、すぐにセッション B から起動された場合、2 つのオカレンスが同時に実行されます。ステートメント トリガーは、行ごとに 1 回ではなく、ステートメントごとに 1 回だけ起動されます (これは、ステートメント トリガーと行トリガーを持つことの要点のようなものです)。そして、ところで - トリガーを実行するには 5 分は長すぎます - トリガーを起動し、作業を完了させ、邪魔にならないようにする必要があります。実行する必要がある 5 分かかるものがある場合は、テーブルを作成します。トリガーを使用して、処理する必要があるものを記述/定義するテーブルにデータを挿入し、トリガーから抜け出します。テーブルからデータを取り出して適切に処理するプログラムが必要になりますが、IMO では、トリガーを 5 分間実行することは許可されません。

YMMV。

共有してお楽しみください。

于 2013-08-08T16:50:34.417 に答える
1

すべての質問に対する答え - トリガーは常にすぐに実行されます。トリガーを同期する理由はまったくありません。実際、これは並行性の高いシステムでは大きな問題となります。Oracle RDBMS が同時実行性を管理する方法については、こちらを参照してください。

ところで、トリガーに大きく依存するもう 1 つの重要な課題があります。変異エラーです。

于 2013-08-08T16:25:34.077 に答える