2

MERGEすべてのセッションで主キー列に異なる値 (以下のスニペットで *** として示されています) を使用しているときに同時s をid実行する場合、2 つのターミナル セッションで手動で実行するとすべて問題ありません。

MERGE
 INTO x
   USING (SELECT *** as id FROM DUAL) MERGE_SRC
     ON (x.id = MERGE_SRC.id)
 WHEN MATCHED THEN UPDATE SET val = val + 1 WHERE id = ***
 WHEN NOT MATCHED THEN INSERT VALUES (***, 99);
COMMIT;

ただし、3 つ以上のスレッドでマルチスレッド負荷テストを実行すると、比較的すぐにORA-08177 with locked table. 何故ですか?(そして、トランザクションがオーバーラップするときに常に発生するとは限らないという点で、なぜ非決定論的なのでしょうか?)

テーブルは次を使用して作成されました

create table x (id int primary key, val int);

SQL Serverところで、同じ実験を実行して、同等のMERGEステートメントで例外をスローすることはありません。これは、同じ行で同時に作業している場合にも当てはまります。

おそらくMERGEがアトミックではなく、シリアライズ可能なモードが楽観的に実行されるため、レースが十分な競合でのみ表示される可能性がありますか? それでも、同じ行を同時に処理していなくても、なぜそれが起こるのでしょうか?

ところで、利用可能な最も厳格なロックを使用してこれを修正しようとする私の試みは失敗しました。したがって、このアトミックを作成する方法についてのアイデアは非常に高く評価されています。分離レベルを緩和すると例外が取り除かれるように見えますが、同じ行に 2 つの更新がある場合に矛盾が発生するリスクがあります (それ以外の場合、最初にシリアル化可能モードでボークするのはなぜですか)。

4

2 に答える 2

4

表示されている例外は、厳密なシリアル化を使用した直接の結果です。同時にアクティブな複数のトランザクションがある場合、それぞれが SET TRANSACTION ISOLATION LEVEL SERIALIZABLE で開始され、それらのいずれかがコミットされると、他のトランザクションは ORA-08177 を取得します。これが厳密なシリアライゼーションの強制方法です。シリアライズ可能なセッションが必要とするテーブルに別のトランザクションがコミットされた場合、データベースは ISOLATION LEVEL SERIALIZABLE で開始されたすべてのセッションで ORA-08177 をスローします。したがって、基本的に、厳密なシリアル化が本当に必要な場合は、次のように ORA-08177 をインテリジェントに処理する必要があります。

DECLARE
  bSerializable_trans_complete  BOOLEAN := FALSE;
  excpSerializable              EXCEPTION;
  PRAGMA EXCEPTION_INIT(excpSerializable, -08177);
BEGIN
  <<SERIALIZABLE_LOOP>>
  WHILE NOT bSerializable_trans_complete
  LOOP
    BEGIN
      SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

      MERGE ...; -- or whatever

      COMMIT;

      bSerializable_trans_complete := TRUE;  -- allow SERIALIZABLE_LOOP to exit
    EXCEPTION
      WHEN excpSerializable THEN
        ROLLBACK;
        CONTINUE SERIALIZABLE_LOOP;
    END;
  END LOOP;  -- SERIALIZABLE_LOOP
END;

シリアル化は魔法ではなく、「無料」でもありません (「無料」とは、「開発者として、適切に機能させるために何もする必要がない」という意味です)。適切に機能させるには、開発者の側でより多くの計画と作業が必要ですが、少なくはありません。共有してお楽しみください。

于 2013-11-12T12:52:24.987 に答える