web-dev-qa-db-ja.com

単一のテーブルに複数の主キーを持つことができますか?

単一のテーブルに複数の主キーを持つことができますか?

347
vaithi

テーブルは、 複合主キー を持つことができます。これは、2つ以上の列から作成された主キーです。例えば:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

更新: これはリンクです 複合主キーのより詳細な説明付き。

504
Adam Pierce

主キーは1つしか持てませんが、主キーには複数の列を含めることができます。

テーブルにユニークインデックスを設定することもできます。これは、ユニークな値を強制し、それらの値の問い合わせをスピードアップするという点で、主キーのように機能します。

179
RB.

テーブルは複数の候補キーを持つことができます。各候補キーは、一意で、一緒になっていて、NOT NULLである列または列のセットです。したがって、候補キーのすべての列に値を指定するだけで、基準を満たす行が1行あるか、行がまったくないと判断できます。

候補キーは、リレーショナルデータモデルの基本概念です。

1つのテーブルに複数のキーが存在する場合は、候補キーの1つを主キーとして指定するのが一般的です。他の候補キーではなく、テーブルへの外部キーが主キーを参照するようにすることも一般的な方法です。

これらのプラクティスをお勧めしますが、リレーショナルモデルには候補キーの中から主キーを選択する必要があるものは何もありません。

34
Walter Mitty

これは主な質問と@ Kalmiの質問に対する回答です。

複数の自動生成列を持つことのポイントは何でしょうか。

以下のこのコードは複合主キーを持ちます。その列の1つは自動増分されます。これはMyISAMでのみ機能します。 InnoDBはエラー「 ERROR 1075(42000):不正確なテーブル定義です。自動列は1つしかないため、キーとして定義する必要があります 」。

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+
13
Eye

主キーは、「主」と暗黙のうちに論理モデルに関連付けられているため、非常に不幸な表記です。私はこのようにそれを使わないようにします。代わりに、物理モデルの代理キーと論理モデルの自然キーを参照します。

すべてのエンティティの論理モデルに、そのエンティティのキ​​ーを構成する「ビジネス属性」のセットが少なくとも1つあることが重要です。 Boyce、Codd、Dateなどは、リレーショナルモデルでこれらを候補キーと呼んでいます。これらのエンティティ用のテーブルを作成すると、それらの候補キーがそれらのテーブル内の自然キーになります。ユーザーがテーブル内の行を一意に識別できるのは、これらのNaturalキーによってのみです。代理キーは常にユーザーに対して非表示にする必要があります。これは、代理キーにはビジネス上の意味がないためです。

しかし、私たちのテーブルの物理モデルは多くの場合、代理キーなしでは非効率的です。非クラスタ化インデックスの非対象列は、(一般的には)クラスタ化インデックスへのキールックアップによってのみ見つけることができます(ヒープとして実装されているテーブルはしばらく無視してください)。利用可能なNatural Keyが広い場合、this(1)は非クラスタ化リーフノードの幅を広げ、その非クラスタ化インデックスのシークとスキャンのためのストレージ要件と読み取りアクセスを増加させます。 (2)クラスタード・インデックスからのファンアウトを減らしてインデックスの高さとインデックスのサイズを増やし、ここでもクラスタード・インデックスの読み取りとストレージ要件を増やします。 (3)クラスタ化インデックスのキャッシュ要件が増えます。他のインデックスやデータをキャッシュから追い出します。

これが、「主キー」としてRDBMSに指定された小さな代理キーが有益であることを証明するところです。非クラスタ化インデックスからクラスタ化インデックスへのキールックアップおよび関連テーブルからの外部キールックアップに使用されるように、クラスタリングキーとして設定すると、これらのすべての不利な点がなくなります。クラスター化インデックスのファンアウトは、クラスター化インデックスの高さとサイズの縮小、クラスター化インデックスのキャッシュ負荷の軽減、任意のメカニズムによるデータアクセス時の読み取りの減少(インデックススキャン、インデックスシーク、非クラスター化キールックアップ、外部キールックアップ)の減少また、テーブルのクラスタ化インデックスと非クラスタ化インデックスの両方に必要な記憶領域を減らします。

これらの利点は、代理キーが小さい場合とクラスタリングキーの両方の場合にのみ発生することに注意してください。クラスタリングキーとしてGUIDが使用されている場合は、利用可能な最小のNaturalキーが使用されている場合よりも状況が悪化することがよくあります。テーブルがヒープとして構成されている場合、8バイト(ヒープ)のRowIDがキー検索に使用されます。これは16バイトのGUIDよりは優れていますが、4バイトの整数よりもパフォーマンスが劣ります。

ビジネス上の制約からGUIDを使用する必要がある場合は、より優れたクラスタリングキーを検索するよりも価値があります。例えば、小さなサイト識別子と4バイトの "site-sequence-number"が実現可能であれば、その設計は代理キーとしてのGUIDよりも優れたパフォーマンスを与えるかもしれません。

ヒープ(おそらくハッシュ結合)の結果として優先ストレージが使用されるようになった場合は、より広いクラスタリングキーのコストをトレードオフ分析にバランスさせる必要があります。

この例を考えてみましょう:

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

タプル " (P_Id、LastName) "は一意性制約を必要とし、長いUnicode LastNameに4バイトの整数を加えたものである可能性がある場合、(1)宣言的にこの制約を " ADDとして強制することが望ましい。 CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED(P_Id、LastName) "と(2)は、小さい代理キーを別々にクラスタ化インデックスの" 主キー "として宣言します。注目すべきことは、Anitaがこの制約にLastNameを追加することだけを望んでいることです。これは、すべてのフィールドがそのフィールドでカバーされているため、クラスタ化インデックスでは不要です。

SQL Serverで主キーをクラスタ化されていないものとして指定することは、残念な歴史的状況です。これは、論理モデルからの「優先自然キーまたは候補キー」という意味と、モデル私の理解するところによれば、もともとSYBASE SQL Serverは、物理モデルの「ストレージ内のルックアップキー」として、ヒープインデックスでもクラスタ化インデックスでも、常に4バイトのRowIDを使用していました。

7
Pieter Geerkens

他の人が指摘したように、複数列の主キーを持つことは可能です。ただし、キーによって導入されない 機能的依存関係 がある場合は、 正規化 あなたの関係を考慮する必要があります。

例:

Person(id, name, email, street, Zip_code, area)

id -> name,email, street, Zip_code and area間には機能的な依存関係がある可能性がありますが、多くの場合、Zip_codeareaに関連付けられているため、Zip_code -> area間には機能的な依存関係があります。

したがって、それを別のテーブルに分割することを検討できます。

Person(id, name, email, street, Zip_code)
Area(Zip_code, name)

そのため、 第3正規形 と一致します。

6

(たくさん勉強しています)

主キーは1つだけです。
しかし、あなたは複数の代替キーを持つことができます。

簡単に言えば、これは事実です。

  • テーブルにはcanが複数のCandidate keys(行を一意に識別するための最小の列)あります。

    • 候補キーの1つは、特に選択で、Primary Keyと呼ばれます。
    • すべてのother候補キーは代替キーと呼ばれます
      • 主キーと代替キーはどちらも複合キーにすることができます(2列以上)。

出典:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org/wiki/Compound_key

主キーはレコードを一意に識別するキーで、すべてのインデックスで使用されます。これがあなたが一つ以上を持つことができない理由です。また、通常は子テーブルへの結合に使用されるキーですが、これは必須ではありません。 PKの真の目的は、データの変更が正しいレコードに影響を与え、インデックスを作成できるように、何かを使ってレコードを一意に識別できるようにすることです。

ただし、1つの主キーに複数のフィールドを入れることができます(複合PK)。これはあなたの結合を遅くし(特にそれらがより大きな文字列型フィールドである場合)そしてあなたのインデックスを大きくしますが、パフォーマンスと設計の点ではケースによってそれを取るので、いくつかの子テーブルで結合をする必要性を取り除くかもしれませんケースベース。これを行うと、各フィールド自体は一意ではありませんが、それらの組み合わせは一意です。複合キー内の1つ以上のフィールドも一意である必要がある場合は、一意のインデックスが必要です。ただし、1つのフィールドが一意であれば、これがPKのより良い候補になる可能性があります。

今は時々、あなたはPKのための複数の候補者を持っています。この場合は、PKとして1つを選択するか、代理キーを使用します(この場合は個人的に代理キーを使用します)。そして(これは重要です!)あなたはPKとして選ばれなかったそれぞれの候補キーにユニークなインデックスを追加します。データが一意である必要がある場合は、PKであるかどうかにかかわらず一意のインデックスが必要です。これはデータの完全性の問題です。 (代理キーを使用するときはいつでもこれが当てはまります。候補キーに一意のインデックスを作成するのを忘れているため、代理キーに問題が生じることがあります。)

複数の代理キーが必要な場合があります(通常、それらがある場合はPKです)。この場合あなたが欲しいものはより多くのPKのものではなく、それは自動生成されたキーを持つより多くのフィールドです。ほとんどのDBはこれを許可していませんが、それを回避する方法があります。最初の自動生成キー(たとえばField1 * -1)に基づいて2番目のフィールドを計算できるかどうか、またはおそらく2番目の自動生成キーが必要かどうかを検討するには、関連テーブルを作成する必要があります。関連テーブルは、1対1の関係にあります。親テーブルから子テーブルにPKを追加し、次にテーブルに新しい自動生成フィールドを追加し、次にこのテーブルに適したフィールドを追加することで、それを強制できます。次に、2つの鍵のうちの1つをPKとして選択し、もう一方に固有の索引を付けます(自動生成フィールドはPKである必要はありません)。そして親テーブルにあるフィールドにFKを必ず追加してください。通常、子テーブルに追加のフィールドがない場合は、2つの自動生成フィールドが必要だと思う理由を調べる必要があります。

2
HLGEM

2つの主キーを同時に持つことはできません。しかし、(あなたが複合キーでケースをめちゃくちゃにしていないと仮定して)、あなたが必要とするかもしれないものは一つの属性をユニークにすることであるかもしれません。

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

ただし、リレーショナルデータベースでは、「スーパーキー」はテーブル内のタプルまたは行を一意に識別する属性のサブセットです。 「キー」は、キーから属性を削除してそのキーを「スーパーキー」にしないようにするという追加のプロパティを持つ「スーパーキー」です(または単に「キー」は最小のスーパーキーです)。さらにキーがある場合、それらはすべて候補キーです。候補キーの1つを主キーとして選択します。そのため、1つのリレーションまたはテーブルに対する複数の主キーについて話すことが矛盾しています。

「主キー」という用語は、自動メカニズムによってその値が生成される正確に整数の列を意味するために使用されています。たとえば、MySQLではAUTO_INCREMENT、Microsoft SQL ServerではIDENTITYです。この意味で主キーを使用していますか?

もしそうなら、答えはあなたが使用しているデータベースのブランドによって異なります。 MySQLでは、これはできません。エラーが発生します。

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

他のブランドのデータベースでは、テーブル内に複数の自動生成列を定義できます。

2
Bill Karwin

良い技術的な答えは私ができるよりも良い方法で与えられました。私はこのトピックに加えることができるだけです:

あなたが許されない/受け入れられない何かが欲しいなら、それは一歩後退する正当な理由です。

  1. 受け入れられない理由の核心を理解する。
  2. ドキュメンテーション/ジャーナル記事/ウェブなどでもっと掘り下げる.
  3. 現在の設計を分析/レビューし、重大な欠陥を指摘します。
  4. 新しい設計中のすべてのステップを検討してテストします。
  5. 常に先を見越して、アダプティブソリューションを作成してください。

誰かに役立つことを願っています。

1
Tom Lime