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


127

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

新しいプロジェクト用に新しいデータベースを設計していますが、ジレンマがあります。

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

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

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


2
ここで説明されているいくつかの追加の考慮事項があります(カバリングインデックスの追加のコンテキストではあります)-dba.stackexchange.com/questions/21554/…– StuartLC '30
07/30

注:SQLiteは、レガシーの問題による一般的な標準に対して、主キーをnullにすることができるという点で異なります。sqlite.org/lang_createtable.html
bitinn

回答:


168

ユニークインデックスとは何ですか?

列の一意のインデックスは、その列のインデックスであり、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'が重複しています

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

MySQLでは、一意の制約により複数のNULLが許可されます。

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

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

同じこと:

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

異なる点:

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

4
一意のインデックスは列のインデックスであり、 1つの一意のインデックスまたは主キーに複数の列を含めることができるため、完全に正確ではないことに注意してください。
Alex Jasmin、

2
@Alexandre Jasmin:おかげで修正。複数列の部分については後述します。
Mark Byers、

nullに関して、ANSI標準では、一意の制約が設定されたデータセットで複数のnull値を使用できます。これは、OracleおよびPostgreSQLでの実装でもあります。SQL Serverは1つのnull値しか許可しないと思います。
David Aldridge 2013

3
それでも、主キーを使用するときや一意のインデックスを使用するときのように、それがわかりませんでした または、同じ状況で両方にある可能性があります。
アミット2016年

33

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

主キーは一意です

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

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

一方、その人には一意の電子メールがあるかもしれませんが、その人を特定することはできません。

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


リレーションシップテーブルで:人工的な主キー(たとえば整数)を使用して新しい列を導入することを意味しますか、それとも合成主キー(person_id、car_id)を使用しますか?

3
主キー(person_id、car_id)が最適です。しかし、私は通常、新しい列を作成します。それによってオーバーヘッドが生じることを確認してください。しかし、それは良いと考えました。後のシナリオで特定の関係に関連するかどうかはわかりません。
フィリップエクバーグ

1
代理主キーが複合/結合テーブルに対して行うもう1つのことは、手動タスクの保守を容易にすることです。
ロバートC.バース

2
子供がいる場合は、主キーだけが必要です。値が何も使用されていないのに値がどこにも表示されない場合、列とシーケンスを追加するのはなぜですか?AccessがPKを要求しないようにするための作業です。子供のレコードを識別する必要がある場合はPKを作成します。それ以外の場合は無駄です。

3
それが関係と何の関係もない場合、それは何と関係があるのでしょうか?あなたはフィールドを指して、それが主要だと言います。そして?それから何が起こりますか?そして、自然なpkがない場合は、列とシーケンス、トリガーなどをすべて追加します。一部はプライマリである必要があります。私は理由もなくルールを避けます。

10

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

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

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

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

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


それは私の地獄を怖がらせます(最初の引用)。どうして?私のPKである任意のIDを持つ人物テーブルがありますが、電話、電子メール、およびSSNにUKを追加することにしました...したがって、4つの異なるテーブルが4つの異なる列で人物に結合しますか?一貫性を保つために得られる可能性のある柔軟性はすべて忘れると思います。

5

自然キーではなく代理主キーをいつ使用するかの選択は難しいです。常に、または決して、などの回答が役立つことはほとんどありません。状況によると思います。

例として、次の表があります。

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)とトランザクションテーブル(drive_through)があります。toll_boothそれは変化に保証されていない全く自然な属性を持っていないため、表には代理キーを使用しています(名前を容易に変更することができます)。carsそれは、非変化の一意の識別子を持っているので、テーブルは自然主キーを使用して(vin)。のdrive_throughトランザクションテーブルには、簡単に識別のための代理キーを使用するだけでなく、レコードが挿入された時点で一意であることが保証されている属性の一意性制約を持っています。

http://database-programmer.blogspot.comには、この特定のテーマに関する優れた記事がいくつかあります。


4

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

@MrWigglesと@Peter Parkerの回答に一部の情報のみを追加するには、たとえばテーブルに主キーがない場合、一部のアプリケーションでデータを編集できません(データがないとデータを編集/削除できないなどと表示されます)主キー)。PostgresqlではUNIQUE列に複数のNULL値を含めることができますが、PRIMARY KEYではNULLは許可されません。また、コードを生成する一部のORMでは、主キーのないテーブルで問題が発生する場合があります。

更新:

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


新しい行が挿入されたり、その列が更新されたりすると、オーバーヘッドが発生します。

3

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


3
テーブルは、主キーではなく、クラスター化インデックスで並べ替えられます。
レイブイセン2009年

1
ほとんどの場合、主キーをクラスター化インデックスに設定します。
Ray Booysen、2009年

これは私たちが知っているが、多くの場合、本当に悪いアイデアでない限り、私たちのコースのホットスポットと私たちのテーブルのアンバランス指標の木、...のような
マイク・ウッドハウス

1
それは常に本当に悪い考えではありません。データを知り、RDBMSを知り、選択肢の意味を知ってください。選択が常に良いか悪いかはめったにありません。常に1の場合、データベースはそれを強制または禁止します。「依存する」ので、彼らはあなたに選択を与えます。

2

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


2

値にNULLを許可しない限り、それらは同じように処理される必要がありますが、値NULLはデータベースでは異なる方法で処理されます(AFAIK MS-SQLでは複数のNULL値を許可しないため、mySQLとOracleではこれを許可しています(列がUNIQUEの場合)したがって、この列を定義する必要ありますNOT NULL UNIQUE INDEX


1
MS-SQLでは、すべてのRDBMSと同様に、一意のインデックスを持つ列で複数のNULL値を使用できます。NULLは値ではないため、2番目のNULLを挿入すると、既存のNULLと一致することはありません。式(NULL == NULL)はtrueまたはfalseに評価されず、NULLと評価されます。
gregmac 2009年

MSがこれに従うかどうか、gregmacよりもわかりませんでした。私はこれでいくつかのMS Quirksを思い出しましたが、数年前(2000年以前)で、古いAccess-DB 咳で
Peter Parker、

2

リレーショナルデータ理論には主要なキーなどは存在しないため、実用的なレベルで質問に回答する必要があります。

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

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

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


MS SQL Serverの主キーは常にUNIQUEとNOT NULLの両方です。たとえば、実際には単なる一意のインデックスですが、NULLにはできないという制限が追加されています。
marc_s 2009年

Oracleは、一意でないインデックスを使用して一意制約を適用できます。MSSSができなかったとしたら、私は驚きます。「本当にユニークなインデックスだ」と言うのは悪いことです。

「多くの場合、外部キーの列にインデックスを宣言すると、結合が速くなります。」これは、可能な場合はハッシュ結合が優先されるデータウェアハウジングの世界ではほとんどの場合当てはまりません。
JAC2703

OPは倉庫について言及していません。ハッシュロインがSQLサーバーでどのように機能するのかわかりません。倉庫の更新時に実行できる作業の量。
Walter Mitty、

2

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

すでに述べたように、CLUSTERED INDEXはテーブル内のデータを物理的に並べます。

つまり、クラスター化インデックスを含むテーブルで挿入または削除を行う場合、データを変更するたびに(ほとんどの場合、FILL FACTORによって異なります)、物理テーブルを更新してソートを維持する必要があります。

比較的小さなテーブルでは問題ありませんが、GBに相当するデータが含まれているテーブルにアクセスすると、挿入や削除が並べ替えに影響し、問題が発生します。


では、利点は何ですか?ソートされたクエリは高速ですか?これは、ほとんどのデータを1回(またはまれに)書き込み、常にそれをクエリする場合のユースケースに適していますか?
バッファロー

1

数値の主キーなしでテーブルを作成することはほとんどありません。一意でなければならない自然キーもある場合は、それに一意のインデックスも付けます。結合は、整数のマルチカラム自然キーよりも高速です。データを変更する必要があるのは1か所のみです(自然キーは更新する必要がある傾向があり、主キーと外部キーの関係にある場合、これは悪いことです)。レプリケーションが必要な場合は、整数ではなくGUIDを使用しますが、特にJohn SmithとJohn Smithを区別するためにキーを表示する必要がある場合は、ほとんどの場合、ユーザーが読み取り可能なキーを使用します。

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


「数値の主キーなしでテーブルを作成することはほとんどありません」:なぜ常に数値なのですか?主キーは数値である必要はありません(ちなみに、AUTO_INCREMENTである必要はありません)。
Hibou57 2013

@ Hinou57。自然キーが実際に一意であることはめったになく、ほとんど常に変更可能であることを発見しました。さらに、整数での結合は、一般的に、varcharhrr自然キーまたはより悪い複合キーでの結合よりもはるかに高速です。ほとんどの場合それらを使用しません。これは、データベースに保存する情報の種類によって異なる場合がありますが、私個人の経験では、時間の経過とともに自然キーが非常に信頼できないことがわかりました。
HLGEM 2013

返信HLGEMをありがとう。信頼できないとはどういう意味ですか?パフォーマンス?(それがデータの整合性という意味での信頼性の問題ではないことを願っています)。整数のキーや短いVARCHARのようなより自然なキーを使用しても、ハッシュは最も単純なDBエンジンでもあらゆる場所で使用されるため、わずかな違いになる可能性があるため、私はあなたの言葉に少し驚いています。
Hibou57 2013

彼らはそうであるはずであるにもかかわらずそれらが確実に一意ではないので、彼らは多くの場合に信頼できません。それらは変更され、更新された何百万ものレコードに影響を与える可能性があるため、信頼できません。これは、さまざまな種類の情報に関するデータを格納する何百ものデータベースからデータを表示または管理またはクエリした経験です。
HLGEM 2013

1

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

残っている唯一の違いは、複数の主キーを持つことはできませんが、nullでない一意のインデックスが複数ある可能性があることです。

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

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


0

一意のインデックスは1つのNULL値を持つことができます。NON-CLUSTERED INDEXを作成します。主キーにNULL値を含めることはできません。CLUSTERED INDEXを作成します。


0

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


-1

それが私次第だったら...

データベースとアプリケーションの要件を満たす必要があります。

自動インクリメントの整数またはロングID列をすべてのテーブルに追加して主キーとして機能させると、データベースの要件に対応できます。

次に、アプリケーションで使用するために、テーブルに他の一意のインデックスを少なくとも1つ追加します。これは、employee_id、account_id、customer_idなどのインデックスになります。可能であれば、このインデックスは複合インデックスであってはなりません。

複合インデックスよりもいくつかのフィールドのインデックスを個別に優先します。データベースは、where句にこれらのフィールドが含まれる場合は常に単一フィールドインデックスを使用しますが、フィールドを正確に正しい順序で指定した場合にのみ複合を使用します。つまり、指定しない限り、複合インデックスの2番目のフィールドを使用できません。 where句の最初と2番目の両方。

私はすべて計算型または関数型のインデックスを使用することに賛成です-複合インデックスではなくそれらを使用することをお勧めします。where句で同じ関数を使用すると、関数のインデックスを非常に簡単に使用できます。

これにより、アプリケーション要件が処理されます。

他の非プライマリインデックスは、実際にはそのインデックスキー値の、rowid()ではなくプライマリキー値へのマッピングである可能性が高いです。これにより、これらのインデックスを再作成することなく、物理的な並べ替え操作と削除を実行できます。

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