web-dev-qa-db-ja.com

すべてのテーブルに単一フィールドの代理/人工主キーがあるべきですか?

サロゲート/人工キーの一般的な利点の1つは理解しています。変更されないため、非常に便利です。これは、それらが「人工的」である限り、それらが単一フィールドであっても複数フィールドであっても当てはまります。

ただし、各テーブルの主キーとして自動インクリメント整数フィールドを持つことは、ポリシーの問題であるように見える場合があります。これは常に、このようなsingle-fieldキーを使用するのに最適なアイデアであり、その理由(または理由)は何ですか?

明確にするために、この質問は人工的なものと自然なものではなく、すべての人工的なキーをsingle-fieldにするかどうかについてです

番号。

単一フィールドのキーが複合キーよりも劣る場合は確かにあると思います少なくとも外部キーの目的では。必要に応じて、単一フィールドの代理キーも必要ないというわけではありませんが、個人的には、主キーと呼ばれる外部キーのターゲットとして最も頻繁に使用されるキーを好みます

次の例で私のポイントを説明しようとします。

  • brandはカーマーキーです。例:フォード、トヨタなど
  • dealerは、ブランドに関連付けられた実際のディーラーです(例:Fordのみを販売するFordディーラー)。
  • modelは車のタイプです。例:フォードフォーカス、フォードフィエスタなど
  • stockは、各ディーラーの現在の前庭の車両数です

次のようにdealermodelの単一フィールド代理キーを作成すると、

create table brand( brand_id integer primary key );

create table dealer( dealer_id integer primary key, 
                     brand_id integer references brand )

create table model( model_id integer primary key, 
                    brand_id integer references brand )

create table stock( model_id integer references model, 
                    dealer_id integer references dealer, 
                    quantity integer,
                      primary key(model_id, dealer_id) )

その後、Ford stockを「Toyota」モデルにリンクするdealerに行を挿入できます。 brand_id references brandstockに追加しても、問題はさらに悪化します。一方、次のように外部キーを主キーの一部として保持するとします。

create table brand( brand_id integer primary key );

create table dealer( brand_id integer references brand, 
                     dealer_id integer, 
                       primary key(brand_id, dealer_id) )

create table model( brand_id integer references brand, 
                    model_id integer, 
                      primary key(brand_id, model_id) )

create table stock( brand_id integer, 
                    model_id integer, 
                    dealer_id integer, 
                    quantity integer,
                      primary key(brand_id, model_id, dealer_id),
                      foreign key(brand_id, model_id) references model,
                      foreign key(brand_id, dealer_id) references dealer )

「フォード」ディーラーが「フォード」車のみをストックできるというルールは、モデルによって自然に適用されます。

「複合キー」の例では、好みに応じてdealer_idが一意である場合とそうでない場合があることに注意してください。一意である必要はありません(つまり、代替キー)。ただし、一意にすることで失われることはほとんどなく(おそらく少しのストレージスペース)、非常に便利なため、通常は次のように設定します。

create table dealer( brand_id integer references brand, 
                     dealer_id serial unique, 
                       primary key(brand_id, dealer_id) )

いいえ、常にというわけではありませんが、ほとんどの場合はそうです

これらは、代理キーまたは人工キーが不要な状況です。

  • 純粋な交差テーブルno交差が外部キーのターゲットになるリスクがあり、交差が独立した属性(つまり、何か)を引き付けるリスクがほとんどまたはまったくない場合2つの親テーブルに対するFK以外の場合)、FKの組み合わせをPKとして使用することで、かなりの自信を得ることができます。
  • 静的ビジネスキーを持つルックアップテーブル。ルックアップがある場合
    外部に固定された一意のビジネスキーを持つテーブル
    ビジネスであり、変化する可能性がまったくない
    実用的な目的。ビジネスキーを直接使用すると、
    もっと簡単です。例として、州または州のリストがあります。
    コードまたはANSI標準番号のリストなど.
  • 複数の独立したソースから統合されたデータを含むテーブル。システムに多数のデータソースがあり、それらを1つのテーブルにまとめる必要がある場合(本社など)、ソースシステムキーの値とソースシステムが何であるかを示すコードを含む複合キーが必要になる場合があります。

古い忠実な単調増加整数代理キーが理想的でない状況もいくつかあります。英数字のサロゲートであるキーを持つことができます。これらには以下が含まれます。

  • 複数の独立したソースからのデータをマージする必要がある状況。キーの衝突を回避するには、IDENTITYキーの代わりにGUIDを使用します。
  • 数値以外のキー表現を使用せざるを得ない状況。ナンバープレートデータベースがあるとします。キーは、純粋な数字ではなく英数字の値にすることもできます。
  • 外部要件によって、キー値に圧縮を適用する必要がある状況。 int32に10桁を使用する代わりに、6つの基本36桁を使用できます。

なぜほとんどの場合はい?その質問に対する最も基本的な答えは、テーブルの主キー値を変更する必要がある場合、それは純粋な地獄であるということです。 almostユーザーが見ることができるものはすべて、ある時点で更新される可能性があるため、目に見えるキー値を使用すると、純粋に地獄を引き起こします。サロゲートキーを使用すると、このトラップに陥ることはありません。

そうは言っても、YAGNIにはこの概念を適用する余地があることを忘れないでください。 IDENTITYキーを含むコードテーブルをスキーマの隅々まで押し込む必要はありません。従業員テーブルの男性の性別の記号をMからXに変更する必要があると誰かが判断した場合に備えて、なんかばかげています。

29
Joel Brown

"場合によります"

はい:自然キーの幅が広く、数値でない場合は、サロゲートIDENTITY/AUTONUMBERフィールドが適しています。注:これは、SQL ServerやSybaseなどでデフォルトで発生する「PK」とクラスター化インデックスの融合を前提としています。

いいえ:2つの親キーで十分な場合は、テーブルの数が多くなります。または、自然キーが短く固定長である場合(通貨コードなど)

もちろん、脳死したORM(read:(n)Hibernate)はこれらのルールに勝ることがあります...

編集:もう一度質問を読む

2つの代理親キーを持つ多/多テーブルには、複数列のPKがあります。
ただし、別のサロゲート列は必要ありません。

テーブルにサロゲート(IDENTITYなど)キーがある場合、複数の列である必要はありません。

サロゲートを含むスーパーキーを持つことができますが、これは他のルールを適用することになります(例 サブタイプ

13
gbn