sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLとActiveRecordが競合状態を副選択

    オプションは次のとおりです。

    • SERIALIZABLEで実行 隔離。相互依存トランザクションは、シリアル化に失敗したため、コミット時に中止されます。多くのエラーログスパムが発生し、多くの再試行が行われますが、確実に機能します。

    • UNIQUEを定義する あなたが指摘したように、制約と失敗時に再試行します。上記と同じ問題。

    • 親オブジェクトがある場合は、SELECT ... FOR UPDATEを実行できます。 maxを実行する前の親オブジェクト クエリ。この場合、SELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATEbarを使用しています すべてのfooのロックとして sそのbar_id 。そうすれば、カウンターインクリメントを実行しているすべてのクエリがこれを確実に実行する限り、続行しても安全であることがわかります。これは非常にうまく機能します。

      これでも、呼び出しごとに集計クエリが実行されます。これは(次のオプションごとに)不要ですが、少なくとも上記のオプションのようにエラーログをスパムすることはありません。

    • カウンターテーブルを使用します。これが私がすることです。 barのいずれか 、またはbar_foo_counterのようなサイドテーブル 、

      を使用して行IDを取得します
      UPDATE bar_foo_counter SET counter = counter + 1
      WHERE bar_id = $1 RETURNING counter
      

      または、フレームワークがRETURNINGを処理できない場合は、効率の低いオプションです。 :

      SELECT counter FROM bar_foo_counter
      WHERE bar_id = $1 FOR UPDATE;
      
      UPDATE bar_foo_counter SET counter = $1;
      

      次に、同じトランザクションで 、生成されたカウンター行をnumberに使用します 。コミットすると、そのbar_idのカウンターテーブルの行 次のクエリで使用できるようにロックが解除されます。ロールバックすると、変更は破棄されます。

    barに列を追加する代わりに、カウンター専用のサイドテーブルを使用するカウンターアプローチをお勧めします。 。これはモデル化がよりクリーンであり、barで作成される更新の膨張が少ないことを意味します 、barへのクエリを遅くする可能性があります 。




    1. INSERTでIDを返しますか?

    2. SQL Server2008でテーブルエイリアスを使用してUPDATESQLを作成するにはどうすればよいですか?

    3. Oracleに複数の行を挿入する

    4. Rows_sent:12 Rows_examined:549024-mySQLクエリを最適化する方法は?