web-dev-qa-db-ja.com

多対多(ジャンクション)テーブルに一意のID列は必要ですか?

EFでいくつかのプロジェクトを開始しましたが、結合テーブルやキーなどについて質問がありました。アプリケーションのテーブルと権限のテーブルがあるとします。アプリケーションには多くのアクセス許可があり、各アクセス許可は多くのアプリケーション(多対多)に属することができます。

これで、アプリケーションと権限のテーブルが簡単になりました。

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

しかし、結合テーブルを行うための最良の方法は何ですか?次の2つのオプションがあります。

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

OR

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

あなたはこれを他の方法でやったことで火傷したことがありますか?厳密に好みですか?多くの「違い」がリポジトリパターンによって抽象化されることに気づきました(たとえば、許可オブジェクト全体を作成してアプリケーションに追加することはほとんどありませんが、IDまたは一意の名前または何か)、しかし私は恐怖の物語を探していると思います。

24
solidau

私はあなたが「接合」テーブルではなく「接合」テーブルを意味すると信じています。

ジャンクションテーブルに独自のIDフィールドを設定する必要はありません。このようなIDに参加したり、フィルターを適用したりする必要はありません。マッピングするテーブルのIDでのみ結合またはフィルタリングします。ジャンクションテーブルのIDは、ディスク領域の浪費です。

したがって、「最良の」オプションはIDを回避することです。通常、junctionテーブルには2つのカバーするインデックスがあります。マップされたIDの1つをプライマリソートフィールドとして使用する各カバリングインデックス。

しかし、「ベスト」はロングショットではありません。冗長なIDフィールドがあることは非常に小さな問題です。少量の無駄なディスクにホラーストーリーはありません。とにかくマップされたコンボでクラスター化したくないので、IDはクラスター化インデックスを「盗む」ことはありません。

フレームワークですべてのテーブルにIDが必要な場合は、IDを使用してください。チームのデータベース標準ですべてのテーブルにIDが必要であると定められている場合は、IDを取得してください。そうでない場合は、避けてください。

21
mike30

何年にもわたって、各テーブル "TableName"に、自動生成された主キー "TableNameID"を、ジャンクションテーブルでさえも例外なく与えるという習慣がありました。 「すべてのテーブル」や「一部のテーブル」、または「複数の異なるテーブルの多数の行」に対して何かを行う汎用コードを作成するときに多くのことが簡単になるため、後悔したことは一度もありません。

たとえば、別のテーブルのいくつかの行(またはそれらへの参照)をファイルまたはメモリに(たとえば、ログの目的で)保存するように依頼された場合、1つだけを保存する必要があることを事前に知っていると非常に便利です。テーブル名と正確に1つの整数ID、そして「特別なケース」に対処する必要はありません。

もう1つは、結合されたPKで開始すると、おそらく後で、結合された外部キーが必要になることがあります(ApplicationPermissionsテーブルにFK参照を追加したい場合があるため)。 。次に、次の要件は、このFKを他の属性または外部キーと組み合わせて一意にすることです。これにより、全体的に複雑さが増します。もちろん、最近のほとんどのDBシステムでは処理できないものはありませんが、統一されたソリューションにより、プログラマーの生活がはるかに容易になります。

最後に、SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)のようなステートメントは、単一の列を主キーとして使用してもうまく機能しますが、これまでのところ、結合されたキーでこれを実行できるSQL方言を見たことはありません。このようなクエリは絶対に必要ないことを前もって知っていれば、問題ありませんが、明日このようなSQLで最も簡単に解決できる要件が得られても驚かないでください。

もちろん、ApplicationPermissionsテーブルに数億の行が保持されることが予想される場合は、ApplicationPermissionsIDのようなものを避けることを検討する必要があります。

11
Doc Brown

マイクの答えは良いですが、別のIDフィールドを追加するかしないかを以下に示します。

  1. ジャンクション/結合テーブルに別のIDフィールドを使用することを検討してくださいID以外のフィールドが含まれている場合。これは、それがファーストクラスのエンティティであることを指摘する傾向があります。

  2. APIまたは既存のロジックがエンティティの取得/編集に単一のフィールドを使用する傾向がある場合は、別のIDフィールドの使用を検討してください。これは、他の人が大規模なプロジェクトのコンテキストであなたのコードをフォローするのに役立ちます。

  3. 特定のメリットがない場合は使用しないでください(KISS)。 EFはこのタイプのテーブルの処理方法を知っているため、他の人がこのタイプの関係を理解し​​ようとすると、複合一意制約を見逃すことがあります。また、正規化するときはタプルを一意に定義する可能な限り小さいキーを使用しようとします。 2番目の例では、事実上、2つの個別の主キーの候補があります。

6
Zachary Yates