複数の列の主キーを使用するか、新しい列を追加する必要がありますか?


15

私の現在のデータベース設計では、各列に任意のキーを割り当てる追加の列を作成する代わりに、複数列の主キーを使用して既存のデータ(とにかく一意)を使用しています。私はこれが許可されていることを知っていますが、これが私が慎重に使用し、おそらく回避する可能性のある慣習であるかどうか疑問に思っていました(Cのgotoのように)。

それでは、このアプローチで見られるかもしれない欠点や、単一の列キーが必要な理由は何ですか?


2
私は知らない、これはSOの方が良かったと思う。
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesignerそれはSOに行くこともできますが、質問の焦点は「どうやってXをやるのか」ではなく「このアプローチの賛否両論」にあるようだから、ここでもうまくいくと思います。
アダムリア

@Anna Lear♦:コーディングに直接かつ明確な影響を与える設計決定についての「賛否両論」ですので、SOがより良い場所になると思います。
FrustratedWithFormsDesigner

回答:


8

通常、複数列の主キーを持つテーブルがある場合、それは結合テーブル(多対多)の結果であり、独自のエンティティに昇格しました(したがって、独自のプライマリキーに値します)。結合テーブルはデフォルトでエンティティである必要があると主張する人も多くいますが、それは別の日の議論です。

仮想的な多対多の関係を見てみましょう。

学生* --- *クラス

(学生は複数のクラスに属することができ、クラスは複数の学生を持つことができます)。

これらの2つのテーブルの間には、StudentClass(または記述方法に応じてClassStudent)と呼ばれるジャンクションテーブルがあります。生徒がクラスにいたときのようなものを追跡したい場合があります。したがって、StudentClassテーブルに追加します。この時点で、StudentClassは一意のエンティティになりました...そして、登録など、それを認識するために名前を付ける必要があります。

学生1 --- *登録* --- 1クラス

(学生は多くの登録を持つことができ、各登録は1つのクラス用です(または逆に、クラスが多くの登録を持つことができ、各登録は1人の学生用です)。

これで、過去1年間にChemistry 101クラスに何人の学生が登録されたかなどを照会できます。または、Acme Universityに在学中にJohn Doeが入学したクラスは何ですか?これは個別のプライマリキーなしでも可能ですが、登録用のプライマリキーを取得すると、これらの登録(IDによる)のクエリが簡単になります。合格した学生は何人ですか?

エンティティがPKに値するかどうかの判断は、そのエンティティに対して実行するクエリ(または操作)の量によって決まります。たとえば、クラスの生徒用に完了した課題を添付するとします。このエンティティ(割り当て)をアタッチする論理的な場所は、登録エンティティになります。登録を独自のプライマリキーにすると、割り当てクエリが簡単になります。


1
したがって、StudentClassテーブルに追加します。この時点で、StudentClassは一意のエンティティになりました...そして、登録など、それを認識するために名前を付ける必要があります。これはとても簡単なことですが、これを行うことには大きな価値があります!
ボティス

8

別のidカラムを持つことは理にかなっています。データベーステーブルから何かを取得したい場合は、簡単です。

SELECT whatever FROM table WHERE id=13

FROMテーブルWHERE SELECT col1 = 'val1' AND col2 = 'val2' AND col3 = 'val3'よりも

たとえば、Webアプリケーションでは、次のようなURLに変換されます。

www.somewebsite.com/somepage.php?id=13

またはこのように:

www.somewebsite.com/somepage.php?col1=val1&col2=val2&col3=val3

4
また、いくつかの列ではなく、IDでリンクできる場合は、関連テーブルを追加する方がはるかに簡単です
-CaffGeek

3
申し訳ありませんが、A)白黒ではないため、この時点で-1にする必要があります。ID列を追加すると、その新しいIDをいつどこで生成するかなどのマイナス要素が伴います。さらに、追加の結合またはSELECTクエリが発生する可能性があります。そして、B)、これが実際にどのような種類のURL要件を引き起こすのかはわかりません(悪いフレームワークで作業している場合を除く)。私のURLにはクエリ文字列が含ま?id=13れておらず、もちろん?col1=val1&col2=val2&col3=val3です。
ニコール

2
@renesis:このサイトには、URLにある固有の質問とユーザーがいます。ただし、特定のデータは変更されないため、これは特殊なケースです。
マイケルK

1
@Renesis、ほとんどの(おそらくすべての)最新のデータベースにはauto_increment整数列タイプがあり、IDを自動的かつ安全に生成し、SQLクエリまたはライブラリ関数呼び出しを介してレポートできます。または、分散環境では、大きなランダムハッシュを使用します。いくつかのDB は、テーブルにすでに存在していない場合、非表示の id列を作成します。
GrandmasterB

@Michael-IDが決してURLに含まれるとは言わなかった。もちろんそうです。データの行を表すURLがある場合、そのデータにはおそらく一意のIDが必要です。URLの他の部分がすでにマルチキーの他の部分を提供している場合を除きます。@GrandmasterB私が働いていた(6年以上)どちらの会社も、MySQL(どちらもOracleとSQL Serverをサポート)を使用していましたが、自動インクリメントも大きなランダムハッシュも使用できませんでした。
ニコール

8

基本的に、サロゲートキーを使用するかナチュラルキーを使用するかを尋ねています(この場合、コンポジットナチュラルキーのように聞こえます)。ここに素晴らしい記事があります:http : //www.agiledata.org/essays/keys.html

代理キーは、DBの存続期間中の管理を簡素化するため、代理キーを好みます(キーが意味を変えることの影響を心配する必要はありません。 ただし、DBに多くの「ルックアップ」テーブル(つまり、基本的にキーと値のペアであるテーブル)がある場合、意味のある結果を得るためにこれらのテーブルをクエリに結合する必要があるため、サロゲートキーが扱いにくくなります。

たとえば、住所と国という2つのエンティティがあるとします。

  • 関係は次のとおりです。住所* ----- 1国
  • Countryエンティティは、基本的にはキーと値のペアです(たとえば、US:United States、CA:Canada、MX:Mexicoなど)
  • 米国内のすべての住所についてこの構造を照会するには:

select * from Address where CountryCode = 'US'

  • 代理キーを使用して同じクエリを実行するには:

select Address.* from Address join Country on Address.CountryID = Country.ID where Country.Code = 'US'

自然キーがあまり頻繁に変更されないことを確信していれば、ルックアップテーブルの自然キーと他のすべての代理キーを強制的に指定できます。


5

データへのアクセス方法によって異なります。多くの部分キールックアップ(3つのキーのうち2つだけに基づいてレコードを選択する場合)を行う場合、マルチパートキーを保持する必要があります。OTOH、他のテーブルと1対1の関係がたくさんある場合は、おそらく代理キーを持つ方が理にかなっています。


1

私は常に各テーブルの代理主キーを持っているのが好きです。しかし、私が聞いたように、これを強制する「ハードな」理由は多くありません。

私がこれまでに複数列の自然なキーに噛まれたのは、ORMでした。ときどき、Linq To Entitiesを使用して複数列のプライマリキーで問題が発生することがあります。


1

決して言ってはいけませんが、4つの列に参加するのは大変です。インテリジェントデータを含む列が多いほど、これらの値が変更される可能性が高くなります。カスケード更新で参照整合性を維持するために、データベースをセットアップできます。

一意の値を処理するために、いつでも別のインデックスを作成できます。

ほとんどの場合、パフォーマンスはおそらく無視できますが、surragateキーの有無にかかわらずクエリをテストできます。


0

別のキーを指定する正当な理由を見つけるのは難しいと思いますが、あなたが言ったように、多くの人がそれを入れました。

ファクト/詳細テーブルを処理するとき、私はこれの助けを(特にストレージに関して)見つけません。正規の例として、数量を持つ(customer_key、store_key、product_key)を持つ販売ファクトテーブルは、レコードレベルのキーを持つことはあまり意味がありません。


0

PKを自動インクリメントintにすると、複合キーに実際に重複があることがわかった場合の手間が減ります。


0

Ask Tomで 2002年にさかのぼる良い議論があります。Oracle固有ですが、使用しているデータベースに関係なく、より広い議論が関連しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.