TL; DR:直列化可能性の競合の検出はPg 9.1で劇的に改善されたため、アップグレードしてください。
説明から実際のSQLが何であるか、そしてなぜロールバックを期待するのかを理解するのは難しいです。シリアル化可能な分離を真剣に誤解しているようです。おそらく、すべての述語を完全にテストしていると考えていますが、特に8.4ページではそうではありません。
SERIALIZABLE
トランザクションが連続して実行されたかのように実行されることを完全に保証するわけではありません。実行できるとしても、パフォーマンスの観点からは法外な費用がかかるためです。限定的なチェックのみを提供します。正確に何がチェックされ、どのようにデータベースごと、バージョンごとに異なるため、データベースのバージョンのドキュメントを読む必要があります。
2つのトランザクションがSERIALIZABLE
で実行されている場合に異常が発生する可能性があります モードは、それらのトランザクションが本当に連続して実行された場合とは異なる結果を生成します。
詳細については、Pgでのトランザクション分離に関するドキュメントをお読みください。 SERIALIZABLE
に注意してください Pg 9.1で動作が大幅に変更されたため、Pgバージョンに適したバージョンのマニュアルを必ずお読みください。 これが8.4バージョンです
。特に、13.2.2.1をお読みください。直列化可能な分離と真の直列化可能性
。次に、これを、大幅に改善された述語ロックベースのシリアル化サポートで説明されているものと比較します。ページ9.1ドキュメント
。
次のような擬似コードのようなロジックを実行しようとしているようです:
count = query("SELECT count(*) FROM the_table");
if (count < threshold):
query("INSERT INTO the_table (...) VALUES (...)");
もしそうなら、それは同時に実行されたときにPg8.4では機能しません-それは上記のリンクされたドキュメントで使用されている異常の例とほとんど同じです。驚くべきことに、実際にはPg9.1で動作します。 9.1の述語ロックでさえ集約の使用を捕らえるとは思っていませんでした。
あなたはそれを書きます:
しかし、8.4は、2つのトランザクションが相互に依存していることを検出しません。これは、2つのpsql
を使用して簡単に証明できます。 それをテストするためのセッション。これが機能するのは、9.1で導入された真の直列化可能性だけです。率直に言って、9.1で機能することに驚きました。
Pg 8.4で最大行数を強制するようなことをしたい場合は、 LOCK
テーブル
同時のINSERT
を防ぐため s、手動またはトリガー関数> 。トリガーでそれを行うと、本質的にロックの昇格が必要になるため、頻繁にデッドロックが発生しますが、正常に機能します。 LOCK TABLE my_table IN EXCLUSIVE MODE
を発行できるアプリケーションで実行することをお勧めします。 SELECT
を取得する前に テーブルから取得するため、テーブル上で必要となる最高のロックモードがすでに設定されているため、デッドロックが発生しやすいロックプロモーションは必要ありません。 EXCLUSIVE
SELECT
を許可するため、ロックモードが適切です。 sだけですが、他には何もありません。
2つのpsqlセッションでテストする方法は次のとおりです。
SESSION 1 SESSION 2
create table ser_test( x text );
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM ser_test ;
SELECT count(*) FROM ser_test ;
INSERT INTO ser_test(x) VALUES ('bob');
INSERT INTO ser_test(x) VALUES ('bob');
COMMIT;
COMMIT;
Pg 9.1で実行すると、st commits succeeds then the second
が成功します。 COMMIT`は次のように失敗します:
regress=# COMMIT;
ERROR: could not serialize access due to read/write dependencies among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
HINT: The transaction might succeed if retried.
ただし、8.4で実行すると、両方のコミットが成功します。これは、8.4には9.1で追加された直列化可能性のすべての述語ロックコードがなかったためです。