最近、私は奇妙な問題に遭遇しました。つまり、シリアライズ可能なトランザクションの中で大量挿入(INSERT ... SELECT)を行い、直後変更されたテーブルでSELECTを使用してカーソルを開きます。このカーソルには新しく挿入された行が含まれていると思われましたが、驚いたことにその内容は不規則で、時には新しく挿入された行がすべて含まれていることがあります。Oracle:シリアライズ可能なトランザクションに挿入した直後に選択
私はカーソルを開く前にコミットすることでこの問題を解決しましたが、その動作は私を困惑させました。 intervining commitなしで、同じトランザクション内の挿入後にselectを実際に信頼できるか?または、この動作は何らかの形でトランザクションがシリアライズ可能であることに関係していますか?
フォローアップ再現可能なテストケースを作成しようとすると、インデックス(この場合はプライマリキーインデックス、実際のコードでは通常のインデックス)を追加した後でしかこの動作を取得できませんでした。おそらく問題は、索引の作成に費やされた時間にあります。その結果、SELECTは実際に不完全な索引を使用して結果を取得しますか?とにかく、ここで再現可能なテストケースを行く:この例では
-- Create empty source table
CREATE TABLE TEST_CASE_1 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Add primary key
ALTER TABLE TEST_CASE_1
ADD CONSTRAINT TEST_CASE_1_PK PRIMARY KEY (CONTENT);
-- Create empty destination table
CREATE TABLE TEST_CASE_2 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Example of faulty code
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Populate with 100.000 rows (I used ALL_OBJECTS but any source of 100.000 rows is good)
INSERT INTO TEST_CASE_1
(SELECT ROWNUM
FROM ALL_OBJECTS
WHERE ROWNUM <= 100000);
INSERT INTO TEST_CASE_2
(SELECT *
FROM TEST_CASE_1
WHERE CONTENT > 0);
COMMIT;
END;
、私はTEST_CASE_2も100.000行を持つことが期待されます。このテストケースを再現すると(無負荷データベースで)、私は約400〜500行挿入しました。トランザクションをシリアライズ可能に設定するステートメントを削除すると、正しい100.000行カウントが取得されました。
挿入を実行しているのと同じデータベースセッションでカーソルを開いていますか?実際にデータベースやクライアントアプリケーションのどこでこの作業をしていますか?後者に接続プールがあり、2つのアクションの接続が異なる場合があります。 –
カーソルが同じセッションで開かれています。もともとはカーソルがデータベースで開かれていて.NET実行ファイルで反復されていましたが、問題を特定するためにデータベース内のカーソルを反復したプロシージャーを作成しましたが、その問題がインサートの後のセレクトにあったことを自分自身に納得させる。 – user1578874
これは起こりません。 [the docs](http://docs.oracle.com/cd/E11882_01/server.112/e25789/consist.htm#sthref1189)から 'シリアル化分離レベルでは、トランザクションはトランザクションの時点でコミットされた変更のみを認識します - クエリ自体が開始されず、トランザクション自体によって行われた変更ではないため、独自の変更が表示されるはずです。私が推測するあなたの特定のバージョンのバグかもしれません。コミットすると、アイソレーションレベルが少し無意味に変更されます。再現可能なテストケースを投稿できますか? –