web-dev-qa-db-ja.com

なぜ単一の主キーが複合キーよりも優れているのですか?

Idという名前の単一の主キーを使用するすべてのテーブルを優先して複合キーを拒否するのはなぜですか?一般的に、すべてのORMはこれに従います。

[〜#〜]編集[〜#〜]

RubyをRailsで学び始めたところですが、実用的なアジャイル開発の本には次のような行があります。---Railsはあまりうまく機能しません各テーブルに数値の主キーがない限り。列の名前についてはそれほど煩わしくありません。私が教義を学んでいたときに読んだのと同じ種類の行。

EDIT2このリンクもチェックしてください。私はこのことについてますます混乱しています:--- 複合主キーと一意のオブジェクトIDフィールド

上記のリンクから:-

*主キーは一定で無意味である必要があります。非代理キーは通常、一方または両方の要件を満たしていないため、最終的には

キーが一定でない場合、キーが無意味でない場合は非常に複雑になる可能性がある将来の更新の問題があり、変更される可能性が高くなります。つまり、一定ではありません。上記を参照

簡単で一般的な例を見てみましょう。在庫アイテムのテーブルです。アイテム番号(SKU番号、バーコード、パーツコードなど)を主キーにしたい場合がありますが、1年後にすべてのアイテム番号が変更され、非常に面倒な更新が残ります。データベースの問題...

編集:哲学的よりも実用的な追加の問題があります。多くの場合、何らかの方法で特定の行を見つけて、後でそれを更新するか、もう一度見つけます(またはその両方)。複合キーを使用すると、追跡するデータが増え、WHERE句に再検索または更新(または削除)するための制約が増えます。その間に、キーセグメントの1つが変更された可能性もあります。サロゲートキーを使用すると、保持する値(サロゲートID)は常に1つだけであり、定義上、変更できないため、状況が大幅に簡素化されます。*

24
Mohit Jain

Idという名前の単一の主キーのみを使用する必要があるという包括的なステートメントはないと思います。

ほとんどの人は、PKをユーザー名にして後で正式な名前を変更した場合のように、主キーを変更する必要がないように分離するため、自動生成intとして代理主キーを使用します。新しい名前を反映するには、PK列とすべてのFK列を更新する必要があります。代理主キーを使用した場合は、ユーザーの名前を1か所で更新するだけです(テーブルは名前ではなくintで結合されるため)。

PKはテーブル上に作成するすべてのインデックスに複製されるため、主キーのサイズは重要です。 PKが大きい場合(文字列のように)、インデックスのページあたりのキー数が少なくなり、インデックスはそれを格納するためにより多くのキャッシュメモリを必要とします。 Intsは小さいです。

自動インクリメントintPKを使用すると、行がこの順序で格納され、新しい行を挿入するために戻って行をバンプする必要がないため、クラスター化インデックスに適しています。常にテーブルの最後に追加します。 。

29
KM.

複合キーの使用で遭遇した唯一の実際の制限は、サブクエリでのIN式の使用に関するものです。 IN式のサブクエリは単一の列を返す必要があるため(少なくともT-SQLでは)、これは問題です。

SELECT
    emp.Name,
    emp.UserDomain,
    emp.UserID
FROM
    employee emp
WHERE
    ???? IN (SELECT e.UserDomain, e.UserID FROM ... /* some complex 
                                                       non-correlated subquery 
                                                       or CTE */
            )

もちろん、常に回避策がありますが、それが煩わしい場合もあります。

これは、複合キーを使用することが理にかなっている場所で複合キーを回避する理由にはなりません。

14

両方を使用できます。場合によっては、エンティティ間で関連付けを行うときに、両方のエンティティキーを複合キーとして使用できます。

経験則として、エンティティには生成されたIDを使用し、関係には複合キーを使用します。

8
James Westgate

さて、それは基本的にJOINをシンプルに保つことです-どちらが理解しやすいですか:

SELECT
   p.ID, p.Name, p.City,
   c.ID, c.Country, c.ISOCode
FROM
   dbo.Parent p
INNER JOIN
   dbo.Child c on c.ParentID = p.ID

または

SELECT
   p.ID, p.Name, p.City,
   c.ID, c.Country, c.ISOCode
FROM
   dbo.Parent p
INNER JOIN
   dbo.Child c ON c.ParentName = p.Name
     AND c.ParentCity = p.City
     AND c.ParentCountry = p.Country

複合主キーがある場合、子テーブルからテーブルに参加する人は、それらすべての列を「ドラッグ」する必要があります。これらの列もすべて子テーブルに存在し、JOINステートメントはかなり乱雑です。 JOIN用の単一の(代理でさえある)キーを持っている方がはるかに良いです!

5
marc_s

私は11列の主キーを持つアプリに取り組みました。 1行を更新することを保証したいときはいつでも、リストを何度も何度も再入力するのはいつもとても楽しかったです。これはバグの原因であり、MS-AccessはPKの10列を超える列に対応できませんでした。

大きな複合キーは、テーブルが異種のエンティティを保持していること、または設計者が各エンティティに固有のものが何であるかを実際に確信していないことを意味するデザインのにおいです。 (髪の色、目の色、体重が従業員を一意に識別するのに十分であると仮定するのと同じように、それを機能させるにはますます多くの列が必要になり、最終的にはフィールドが含まれるため、これは良いキーではありません揮発性で、体重のように大きく変化するものや、髪の色が不足している人もいます。)

3
MatthewMartin

他の回答者からの理由のほとんどに同意しますが、単一列の整数キーを好む主な理由は、ユーザーインターフェイスの作成がはるかに簡単になることです。

ある種のリストコントロールを使用してデータ(リスト、リストビュー、コンボボックスなど)を表す場合は、アイテムに格納されている単一の整数値を使用して、各エントリをデータベース表現に一意に関連付けることができます。ほとんどの事前に作成されたコンポーネントでは、すでに各アイテムに整数をアタッチできますが、そうでないコンポーネントの場合は、コンポーネントを拡張してそうするのは非常に簡単です。

サーバーアプリケーションとWebページの間でデータを渡す場合は、複数の値のIDを作成して解析するよりも、データを表すウィジェットのid属性に単一の識別値を格納する方がはるかに簡単です。

2
Larry Lustig
  1. ORMの場合、table_idのような一貫した名前を持つ単一の識別列は、複合キーよりも簡単です。しかし、すべての優れたORMは複合キーをサポートしています。

  2. 単純なPKは、データベースによって簡単に「自動インクリメント」できます。これは、複合キーには当てはまりません。

  3. 単純なPKは、クエリでも簡単に使用できます。参加する必要がある場合は、両方のリレーションの1つの列を使用するだけで済みます。

ただし、これは単純なPKが複合PKよりも優れているということではありません。

1
Exception e

OOプログラミングのオブジェクトは、その内容に関係なくIDを持ちます。リレーショナルデータベースの行(タプル)は、その内容によってのみ識別されます。したがって、実際にORMを実行する場合、つまりオブジェクト指向プログラミング言語からオブジェクトをマッピングする場合リレーショナルデータベースには、オブジェクトがプログラム内に持つフィールドやプロパティとは別のIDを追加で提供する必要があります。ただし、オブジェクトを一意に識別することが1つ以上わかっている場合を除きます。

0
reinierpost

あなたの質問は 代理(または人工)キーと自然キー 代替に強く関連しています。 compositeキーがあまり使用されていないわけではないと思いますが、naturalキー(複合キーまたは単純キー)は、人工キーよりも優先されません。

従来のリレーショナルデータベース理論は、主に「自然」キー(ビジネスドメインの観点から意味を持つもの)を扱い、そのシナリオでは、複合キーが頻繁に見つかります...自然に。

しかし、後年、データベース設計は(排他的ではありませんが)「人工」(代理)キーパターン、通常はビジネス上の意味を持たない連番を支持し、テーブル内のレコード(およびおそらくオブジェクト)を一意に識別するためにのみ機能します。上層)。

0
leonbloy