web-dev-qa-db-ja.com

複合主キーを持つテーブルへのINSERTの同時実行性に関するベストプラクティス?

テーブルusersteams、およびteams_usersジャンクションテーブル(team_IDuser_ID /複合PK)。ユーザーをチームに追加したい場合、パフォーマンス/同時実行の問題に関して、どのオプションが最適ですか?

オプション1)

最初にテーブルをクエリし、リレーションシップが既に存在するかどうかを確認します(リクエストを行ったユーザーに通知するだけの場合)。

オプション2)

挿入中はWHERE EXISTS構文( 2番目の例 )。

オプション3)

UPSERT機能にはPostgres 9.5 Betaを使用してください。 (私は、学校のプロジェクトにベータ版を使用することは、それほど悪い考えではないと思いますか?).

並行性に関してはどのオプションが最適でしょう。私はSQLの経験があまりありません(CRUDアプリケーションの標準的なものだけです)。しかし、私の知る限りでは、最初のオプションでは、ジャンクションテーブルをクエリした直後に、実際にリレーションを自分で挿入する前に、別のユーザーがリレーションシップを挿入できます。ジャンクションテーブルに複合主キーがあるので重複はないと思いますが、例外を発生させて続行するのは悪い習慣だと思います。さらに、私の現在のコードでは、この場合(db例外のため)500 httpステータスを返しますが、これは実際には正しくないようです。

私はデータベース/テーブルを「ロック」することで上記を部分的に解決できると読みましたが、それが正しい方法であるかどうかはわかりません。

最後に、2番目のオプションに関して、競合状態があるかどうかはわかりません。

チームにユーザーを追加したい場合、どのオプションが最適ですか

INSERT INTO teams_users ...そして例外を発生させずに、答えはoption 3です:Postgres 9.5Beta for[〜#〜] upsert [〜#〜]機能。 「学校のプロジェクト」にとって、これはとにかく最良の選択肢です。あなたの学生は最新版を勉強したいと思うでしょう。

INSERT INTO teams_users (team_ID, user_ID)
VALUES (1, 2)
ON CONFLICT ON CONSTRAINT teams_users_pkey DO NOTHING;

どこ teams_users_pkeyは、PK制約の実際の名前です。

これにより、新しい行が挿入されるか、一意のインデックスで重複キー違反が発生する場合は何も行われません。同時書き込みに対して高速かつ安全になるように設計されています。

追加の質問

最後に、2番目のオプションに関して、競合状態があるかどうかはわかりません。

オプション2は:

挿入中はWHERE EXISTS構文(2番目の例)。

それは実際にはWHERE NOT EXISTSあなたのケースではyes、競合状態があります。 2つの並列トランザクションは、特定の組み合わせが実質的に同時に存在しないことを発見し、喜んでそれを挿入しようとする可能性があります。遅い方は固有の違反に遭遇し、エラーになります。アプリケーションがそのような事態に備えることができれば、それほど問題にはなりません。

2

データの整合性が気になる場合(適切なすべてのテーブルにデータが読み込まれる前にデータが読み込まれることを確認してください)、3つの挿入すべてが同じトランザクションブロック内で行われるようにする必要があります。

Begin transaction
Insert 1) insert into users
Insert 2) insert into teams
Insert 3) insert into teams_users
Commit transaction

同じトランザクションブロック内でこれらを実行しない場合、チームとteams_usersが挿入される前に誰かがユーザーから選択する可能性があります。

1
Joishi Bodio