1

2 つの DB テーブル A と B を同期する Oracle 10g 本番 DB でジョブを実行しています。ジョブはテーブル A からデータをフェッチし、テーブル B に挿入します。ジョブは毎日実行され、過去数か月間、本番環境で失敗し始めました。 「データの取得中にエラーが発生しました -54」というエラーが表示されます。ストア プロシージャを確認すると、他のジョブがテーブル A のレコードをロックし、ジョブが同じレコードを処理できない場合に、レコードの問題がロックされているためにジョブが失敗することがわかりました。そこで、以下に示すいくつかの可能な解決策を探し始めました。

  1. レコードを処理できるように、ジョブの実行時間を変更します。ただし、テーブル A は非常に重要であり、常に運用ジョブで使用されるため、これは役に立ちません。また、ユーザーからのリアルタイムの更新があります。

  2. 「No WAIT」の代わりに「SKIP LOCKED」を使用して、ジョブがロックされたレコードをスキップし、正常に実行されるようにします。しかし、ここでの問題は、ロックされたレコード (これは、膨大な実動データと比較して常に無視できるものです) がスキップされた場合、その日のテーブル A と B のデータに不一致が生じることです。ジョブは前日の選択されていないレコードも選択するため、翌日の実行はこの問題を解決します。しかし、ジョブが失敗した日のわずかな不一致は、小さな問題を引き起こす可能性があります

  3. すべてのレコードのロックが解除されて処理されるまで、ジョブを待機させます。しかし、ジョブが待機状態 (長時間実行状態) になる時間を予測できないため、これも問題を引き起こします。

現時点で考えられる解決策の 1 つは、オプション 2 を使用して、テーブル A と B のデータのわずかなずれを無視することです。Oracle 10g Db で、ジョブを失敗せずに長時間実行してすべてのレコードを処理する他の方法はありますか。その上で、技術的な指導を受けたいと思っています。

ありがとうPB

4

1 に答える 1

2

私は例外を処理し(注、独自のものを初期化するかEXCEPTION、処理OTHERSして検査する必要がありますSQLCODE)、スキップされた行のIDを追跡します。そうすれば、利用可能なすべてのレコードが処理されたら、それらを再試行できます。

このようなもの:

DECLARE

  row_is_locked EXCEPTION;
  PRAGMA EXCEPTION_INIT(row_is_locked, -54);

  TYPE t_id_type IS VARRAY(1) OF INTEGER;
  l_locked_ids t_id_type := t_id_type();

  l_row test_table_a%ROWTYPE;

BEGIN

  FOR i IN (
    SELECT a.id
    FROM test_table_a a
  )
  LOOP

    BEGIN

      -- Simulating your processing that requires locks
      SELECT *
      INTO l_row
      FROM test_table_a a
      WHERE a.id = i.id
      FOR UPDATE NOWAIT;

      INSERT INTO test_table_b 
      VALUES l_row;

      -- This is on the basis that you're commiting
      -- to release the lock on each row after you've
      -- processed it; may not be necessary in your case
      COMMIT;

    EXCEPTION

      WHEN row_is_locked THEN
        l_locked_ids(l_locked_ids.LAST) := i.id;
        l_locked_ids.EXTEND();

    END;

  END LOOP;

  IF l_locked_ids.COUNT > 0 THEN
    FOR i IN l_locked_ids.FIRST .. l_locked_ids.LAST LOOP
      -- Reconcile the remaining ids here
      NULL;
    END LOOP;
  END IF;

END;
于 2012-11-21T08:26:11.210 に答える