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


22

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

これで、アプリケーションテーブルとアクセス許可テーブルが簡単になりました。

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

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

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

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

または

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

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

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

回答:


20

「接合」テーブルではなく「接合」テーブルを意味すると思います。

ジャンクションテーブルが独自のIDフィールドを持つ必要はありません。そのようなIDに参加したりフィルタリングしたりする必要はありません。マッピングするテーブルのIDでのみ結合またはフィルタリングします。ジャンクションテーブルのIDはディスク領域の無駄です。

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

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

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


2
さて、IDを追加することは軽微な譲歩であり、潜在的な利点によって簡単に克服されると既に述べたので、すべてのテーブルに一意のIDを持つことは、ほとんどのDBMSおよびORMでベストプラクティスであると考えられます)IDを持たないのではなく、「最良」または「デフォルト」のオプションとしてID持つことを推奨します。
ロバートハーベイ

4
「このようなIDに参加したり、クエリしたりする必要はまったくありません」-テクノロジーの状況で「決して」と言うことは、まさにそのようなことを招くことです。言って、そこにある参加エンティティは、実際aであるため、第4テーブルはまだにテーブルを結合するあなたが参加する時間が(はい、私はそれがより多くの「ジャンクション」テーブルよりもテーブルを「結合」と呼ばれる聞きました)独自のビジネスオブジェクト。
ジェシーC.スライサー

4
@RobertHarvey。IDはエンティティにとって良い習慣です。ただし、ジャンクションは、それ自体がエンティティではなく、多対多リレーションの実装の詳細です。しかし、Jesse C.スライダーが指摘するように、ジャンクションがビジネスエンティティと見なされる場合があります。
mike30

1
「ディスクスペースの無駄。」-一部のエンジン(InnoDB?)は、自分で作成しない場合でも(内部)主キーを作成すると思います。そのため、実際にディスクスペースを持たないことでディスクスペースを獲得できない場合があります。
アレックス

@アレックス。マッピングされたIDに複合PKを配置します。
mike30

11

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

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

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

そして最後に、次のようなステートメントSELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)は主キーとして単一の列でうまく機能しますが、これまでSQLダイアレクトを見たことがありません。事前にこのようなクエリが必要ないことを知っていれば問題ありませんが、明日、この種のSQLで最も簡単に解決できる要件を取得しても驚かないでください。

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


私はあなたの答えを選ぶことになりませんでしたが。私はそれが好きです。ご意見ありがとうございます(賛成)。
-solidau

6

マイクの答えは良いですが、ここに別のIDフィールドを追加するかどうかを説明します。

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

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

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


-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

両方のインデックスと外部キーを作成することを忘れないでくださいPersonIdAddressId

他の人が「より良い」または「あなたがすべき」と思うものに関係なく、これはデータベースを適切に機能させるための最も簡単で簡単な方法です。


1
私は、このアプローチの一つの問題は、スキーマが2ことができますだと思うPersonAddress同じで行をPersonIdし、AddressId値。
サム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.