web-dev-qa-db-ja.com

各外部キー値にシーケンスを実装するにはどうすればよいですか?

PostgreSQL(9.3)データベースでは、AccountsとCustomersの間に1対多の関係があるため、Customersテーブルには、各Customerの主キーのグローバルに一意のIDと、対応するAccount IDがあります。しかし、私はそれぞれにアカウント固有のIDを割り当てたいと思います-各アカウントの最初の顧客の1から始まり、追加の顧客ごとに増分する番号だけ-単にアカウントのユーザーがUIで顧客を参照する簡単な方法として。

私は2つの可能な解決策を考えることができます:

  1. max()集約関数を使用して、アカウントに使用された最後のカスタマーIDを取得し、それをインクリメントします

    • 長所
      • 比較的単純(概念的には少なくとも)
    • 短所
      • 最新の顧客が削除された場合、IDが再利用される可能性があります
      • 新しいレコードに対して同じIDを計算する同時挿入を処理する必要がある
  2. sequence

    • 長所
      • 値の増加を処理するように特別に設計されています
      • 対応するレコードが削除されても、最後に使用された値を記憶します
    • 短所
      • 何らかの方法で新しいアカウントごとに個別のsequenceを作成する必要があります(その後、アカウントが削除された場合は削除されます)。そうでない場合、各アカウントは、顧客IDシーケンスで連続しない値になります。

[〜#〜]更新[〜#〜]

最後のポイントを明確にするために、IDのシーケンスにいくつかのギャップが常に発生します。たとえば、顧客が削除されるとすぐに、それらは期待されます。それとは別に、新しい顧客をいくつか追加するユーザーは、通常、数日おきに追加された場合でも、連続したIDを持つことを期待します。

OTOH、すべてのお客様に単一のsequenceを使用すると、当面、他のアカウント用に作成されたお客様に割り当てられたIDによって導入された、説明のつかない定期的なギャップがほぼ確実に発生する可能性があります。

私はPostgresの専門家ではないので、特にこれらの例をどれほど確実に実装できるかについて心配しています。

これを行う一般的に受け入れられている方法はありますか?

6
David G

_max_customer_id_というテーブルaccountの列を使用して、新しい顧客が来るたびにそれを更新してみませんか?それは私が考えることができる利用可能な最も簡単な解決策であるべきです。

このソリューションでは、並行性に注意する必要があります。ドキュメントを見てください PostgreSQL同時実行の問題:

2つの同時トランザクションが同じキー値を持つ行を挿入しようとすると、2番目のトランザクションは最初のトランザクションが完了するまでブロックされます。最初のトランザクションがコミットした場合、一意性の制約のため、2番目のトランザクションは中止する必要があります。ただし、最初のイベントが中止された場合、2番目のイベントは続行できます。

テーブルの各行にシリアル番号を割り当てたい場合は、
INSERT INTO mytable (id, ...) VALUES( (SELECT MAX(id) + 1 FROM mytable), ...);
これは、テーブル全体を明示的にロックしない限り安全に機能しないため、同時挿入が防止されます。 (MAXはPostgreSQLのテーブル全体をスキャンするため、速度も非常に遅くなります。)

または、別のテーブルに値を配置することもできます。このテーブルには、そのアカウントで使用されている_account_id_および最大_account_specific_id_が含まれます。そうすれば、UPDATEsを使用して並行処理を簡単に処理できます。 同じソース

バリアントは、単一行のテーブルを使用して、割り当てる次のID番号を保持することです。
SELECT next FROM mytable counter FOR UPDATE; UPDATE mytable counter SET next = $next + 1; INSERT INTO mytable (id, ...) VALUES($next, ...);
これは機能しますが(FOR UPDATEを使用している限り)、一度に処理できる挿入トランザクションは1つだけであるという問題があります。カウンター行の暗黙的な書き込みロックがボトルネックです。
[著者はシーケンスの推奨を続けます。]

ただし、シーケンスを使用する2番目のオプションは、新しいシーケンスが本番環境に日常的に挿入されることを意図していないため、この場合はお勧めしません。

3
Simo Kivistö