web-dev-qa-db-ja.com

主キーまたは一意のインデックス?

職場では、主キーの代わりに一意のインデックスを持つ大きなデータベースがあり、すべて正常に機能します。

私は新しいプロジェクトのために新しいデータベースを設計していますが、ジレンマがあります:

DB理論では、主キーは基本的な要素ですが、それでも構いませんが、REALプロジェクトでは両方の長所と短所は何ですか?

プロジェクトで何を使用していますか?

編集: ...そして、MS SQLサーバー上のプライマリキーとレプリケーションはどうですか?

116
Cicik

一意のインデックスとは?

列の一意のインデックスは、その列の2つの異なる行の2つの等しい値を持つことはできないという制約を強制する、その列のインデックスです。例:

 CREATE TABLE table1(foo int、bar int); 
 CREATE UNIQUE INDEX ux_table1_foo ON table1(foo); -foo。
 
 INSERT INTO table1(foo、bar)VALUES(1、2);に一意のインデックスを作成します。 -OK 
 INSERT INTO table1(foo、bar)VALUES(2、2); -OK 
 INSERT INTO table1(foo、bar)VALUES(3、1); -OK 
 INSERT INTO table1(foo、bar)VALUES(1、4); -失敗!
 
キー 'ux_table1_foo'の重複エントリ '1' 

最後の挿入は、値1をこの列に再度挿入しようとすると、列fooの一意のインデックスに違反するため失敗します。

MySQLでは、ユニーク制約により複数のNULLが許可されます。

複数の列に一意のインデックスを作成することができます。

主キーと一意のインデックス

同じもの:

  • 主キーは一意のインデックスを意味します。

異なるもの:

  • 主キーはNOT NULLを意味しますが、一意のインデックスはNULL可能です。
  • 主キーは1つしか存在できませんが、一意のインデックスは複数存在できます。
  • クラスタ化インデックスが定義されていない場合、プライマリキーはクラスタ化インデックスになります。
156
Mark Byers

次のように表示されます。

主キーIS一意

一意の値は要素の表現である必要はありません

意味?;要素を識別するために主キーが使用されます。「個人」がいる場合は、その個人のプライマリである個人識別番号(SSNなど)が必要です。

一方、その人は一意の電子メールを持っているかもしれませんが、その人を識別しません。

リレーションシップテーブル(中間テーブル/接続テーブル)にも主キーがあります。どうして? 「Person」に識別子があり、Carに識別子がある場合は、コーディング時に標準に従うのが好きです。Person-> Carにも識別子が必要です。

30
Filip Ekberg

外部キーは、一意の制約とプライマリキーで機能します。 Books Onlineから:

FOREIGN KEY制約は、別のテーブルのPRIMARY KEY制約にのみリンクする必要はありません。別のテーブルのUNIQUE制約の列を参照するように定義することもできます

トランザクションレプリケーションの場合、主キーが必要です。 Books Onlineから:

トランザクションレプリケーション用にパブリッシュされるテーブルには主キーが必要です。テーブルがトランザクションレプリケーションパブリケーションにある場合、プライマリキー列に関連付けられているインデックスを無効にすることはできません。これらのインデックスはレプリケーションに必要です。インデックスを無効にするには、まずパブリケーションからテーブルを削除する必要があります。

どちらの答えもSQL Server 2005に対するものです。

8
Jonas Lincoln

自然なキーではなく、代理主キーをいつ使用するかの選択は注意が必要です。 「常に」または「決して」などの回答が役立つことはめったにありません。状況に依存することがわかります。

例として、次の表を用意しています。

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

2つのエンティティテーブル(toll_boothsおよびcars)と1つのトランザクションテーブル(drive_through)があります。 toll_boothテーブルは、変更が保証されていない自然な属性がないため、代理キーを使用します(名前は簡単に変更できます)。 carsテーブルは、変化しない一意の識別子(vin)を持っているため、自然の主キーを使用します。 drive_throughトランザクションテーブルは、識別を容易にするために代理キーを使用しますが、レコードの挿入時に一意であることが保証されている属性に一意の制約もあります。

http://database-programmer.blogspot.com には、この特定のテーマに関する素晴らしい記事があります。

5
aekeus

主キーの欠点はありません。

@MrWigglesと@Peter Parkerの回答にいくつかの情報を追加するために、たとえばテーブルにプライマリキーがない場合、一部のアプリケーションでデータを編集できません(最終的には、主キー)。 Postgresqlでは、複数のNULL値をUNIQUE列に含めることができます。PRIMARYKEYはNULLを許可しません。また、コードを生成する一部のORMには、主キーのないテーブルで問題が発生する場合があります。

更新:

私の知る限り、MSSQLの主キーなしで、少なくとも問題なく( details )、テーブルを複製することはできません。

4
empi

リレーショナルデータ理論には主キーというものはないため、実際のレベルで質問に答える必要があります。

一意のインデックスは、SQL標準の一部ではありません。 DBMSの特定の実装は、一意のインデックスを宣言した結果を決定します。

Oracleでは、主キーを宣言すると、ユーザーに代わって一意のインデックスが作成されるため、問題はほとんど意味がありません。他のDBMS製品については説明できません。

主キーを宣言することを好みます。これには、重複を禁止するだけでなく、キー列でNULLを禁止する効果があります。また、エンティティの整合性を強化するためにREFERENCES制約を宣言することも好みます。多くの場合、外部キーの列でインデックスを宣言すると、結合が高速化されます。この種のインデックスは、一般的に一意であってはなりません。

2
Walter Mitty

何かが主キーである場合、DBエンジンに応じて、テーブル全体が主キーでソートされます。これは、他の種類のインデックスのように参照解除を行う必要がないため、主キーの検索がはるかに高速であることを意味します。それに加えて、それは単なる理論です。

2
Ray Hidayat

値にNULLを許可しない限り、同じように処理する必要がありますが、データベースでは値NULLの処理が異なります(MS-SQLでは複数のNULL値を許可していません。 、列が一意の場合)mustこの列を定義するNOT NULL UNIQUE INDEX

2
Peter Parker

他の回答が述べたことに加えて、一部のデータベースとシステムは必須プライマリが存在する場合があります。 1つの状況が思い浮かびます。 Informixでエンタープライズレプリケーションを使用する場合、テーブルがレプリケーションに参加するにはPKが存在する必要があります。

1
tddmonkey

私の理解では、主キーと非null制約を持つ一意のインデックスは同じ(*)です。そして、私は仕様が明示的に述べているか、または暗示するものに応じてどちらかを選択すると思います(あなたが何を表現し、明示的に強制したいのか)。一意性と非nullが必要な場合は、主キーにします。発生する場合、一意のインデックスのすべての部分がnullでなく、そのための要件が​​ない場合は、一意のインデックスにします。

唯一の違いは、複数の主キーを持つことはできませんが、複数の非nullユニークインデックスを使用できることです。

(*)実際の違いを除いて、主キーは、外部キーの定義など、一部の操作のデフォルトの一意のキーになります。例テーブルを参照する外部キーを定義し、列名を提供しない場合、参照されるテーブルに主キーがある場合、主キーは参照される列になります。それ以外の場合は、参照される列に明示的に名前を付ける必要があります。

ここの他の人はDBレプリケーションについて言及していますが、私はそれについて知りません。

1
Hibou57

CLUSTERED INDEXとUNIQUE INDEXESにはいくつかの欠点があります。

すでに述べたように、クラスター化インデックスはテーブル内のデータを物理的に順序付けます。

つまり、クラスター化インデックスを含むテーブルで挿入または削除を行う場合、データを変更するたびに(まあ、ほぼ、フィルファクターに応じて)多くの場合、物理テーブルを更新して並べ替えを維持する必要があります。

比較的小さなテーブルではこれで問題ありませんが、GB相当のデータがあり、挿入/削除がソートに影響するテーブルに到達すると、問題が発生します。

1
Nico Bester

数値主キーなしでテーブルを作成することはほとんどありません。一意である必要がある自然キーもある場合は、一意のインデックスもその上に配置します。結合は、複数列の自然キーよりも整数の方が高速です。データは1か所で変更するだけで済みます(自然キーは主キーと外部キーの関係にある場合、更新が必要になる傾向があります)。レプリケーションが必要な場合は、整数の代わりにGUIDを使用しますが、ほとんどの場合、特にジョンスミスとジョンスミスを区別する必要がある場合は、ユーザーが読み取り可能なキーを好みます。

代理キーを作成しないのは、多対多の関係に関与する結合テーブルがある場合です。この場合、両方のフィールドを主キーとして宣言します。

1
HLGEM

一意のインデックスには、1つのNULL値を設定できます。非クラスター化インデックスを作成します。主キーにNULL値を含めることはできません。クラスター化インデックスを作成します。

0
Chirag

MSSQLでは、クラスター化インデックスで最高のパフォーマンスを得るために、主キーを単調に増加させる必要があります。したがって、ID挿入を伴う整数は、単調に増加しない自然キーよりも優れています。

0
Markus