職場では、主キーの代わりに一意のインデックスを持つ大きなデータベースがあり、すべて正常に動作しています。
新しいプロジェクト用に新しいデータベースを設計していますが、ジレンマがあります。
DB理論では、主キーは基本的な要素ですが、それは問題ありませんが、REALプロジェクトでは、両方の長所と短所は何ですか。
プロジェクトで何を使用していますか?
編集: ...そしてMS SQLサーバー上の主キーとレプリケーションはどうですか?
職場では、主キーの代わりに一意のインデックスを持つ大きなデータベースがあり、すべて正常に動作しています。
新しいプロジェクト用に新しいデータベースを設計していますが、ジレンマがあります。
DB理論では、主キーは基本的な要素ですが、それは問題ありませんが、REALプロジェクトでは、両方の長所と短所は何ですか。
プロジェクトで何を使用していますか?
編集: ...そしてMS SQLサーバー上の主キーとレプリケーションはどうですか?
回答:
ユニークインデックスとは何ですか?
列の一意のインデックスは、その列のインデックスであり、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が許可されます。
複数の列に一意のインデックスを作成することが可能です。
主キーと一意のインデックス
同じこと:
異なる点:
次のように表示されます。
主キーは一意です
一意の値は要素の表現である必要はありません
意味?; 要素を識別するために主キーが使用されます。「個人」がある場合は、個人の主要な個人識別番号(SSNなど)が必要です。
一方、その人には一意の電子メールがあるかもしれませんが、その人を特定することはできません。
リレーションシップテーブル(中間テーブル/接続テーブル)でも、常にプライマリキーを持っています。どうして?まあ私はコーディング時に標準に従うのが好きです。「Person」に識別子があり、Carにも識別子がある場合、Person-> Carにも識別子があるはずです!
外部キーは、一意の制約と主キーで機能します。Books Onlineから:
FOREIGN KEY制約は、別のテーブルのPRIMARY KEY制約にのみリンクする必要はありません。別のテーブルのUNIQUE制約の列を参照するように定義することもできます
トランザクションレプリケーションでは、主キーが必要です。Books Onlineから:
トランザクションレプリケーション用にパブリッシュされたテーブルには、主キーが必要です。テーブルがトランザクションレプリケーションパブリケーションにある場合、主キー列に関連付けられているインデックスを無効にすることはできません。これらのインデックスはレプリケーションで必要です。インデックスを無効にするには、最初にパブリケーションからテーブルを削除する必要があります。
どちらの回答もSQL Server 2005に対するものです。
自然キーではなく代理主キーをいつ使用するかの選択は難しいです。常に、または決して、などの回答が役立つことはほとんどありません。状況によると思います。
例として、次の表があります。
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には、この特定のテーマに関する優れた記事がいくつかあります。
主キーの欠点はありません。
@MrWigglesと@Peter Parkerの回答に一部の情報のみを追加するには、たとえばテーブルに主キーがない場合、一部のアプリケーションでデータを編集できません(データがないとデータを編集/削除できないなどと表示されます)主キー)。PostgresqlではUNIQUE列に複数のNULL値を含めることができますが、PRIMARY KEYではNULLは許可されません。また、コードを生成する一部のORMでは、主キーのないテーブルで問題が発生する場合があります。
更新:
私の知る限り、MSSQLの主キーなしでテーブルを複製することはできません。少なくとも問題はありません(詳細)。
DBエンジンによっては、主キーが何かである場合、テーブル全体が主キーでソートされます。これは、他の種類のインデックスとは異なり、逆参照を行う必要がないため、主キーでの検索がはるかに高速であることを意味します。その上、それは単なる理論です。
値にNULLを許可しない限り、それらは同じように処理される必要がありますが、値NULLはデータベースでは異なる方法で処理されます(AFAIK MS-SQLでは複数のNULL値を許可しないため、mySQLとOracleではこれを許可しています(列がUNIQUEの場合)したがって、この列を定義する必要がありますNOT NULL UNIQUE INDEX
リレーショナルデータ理論には主要なキーなどは存在しないため、実用的なレベルで質問に回答する必要があります。
一意のインデックスは、SQL標準の一部ではありません。DBMSの特定の実装によって、一意のインデックスを宣言した場合の結果が決まります。
Oracleでは、主キーを宣言すると、ユーザーに代わって一意のインデックスが作成されるため、問題はほとんどありません。他のDBMS製品についてはお話しできません。
主キーの宣言を支持します。これには、キー列のNULLを禁止する効果と、重複を禁止する効果があります。また、エンティティの整合性を強化するために、REFERENCES制約を宣言することもお勧めします。多くの場合、外部キーの列にインデックスを宣言すると、結合が高速化されます。この種のインデックスは、一般的に一意であってはなりません。
CLUSTERED INDEXESとUNIQUE INDEXESにはいくつかの欠点があります。
すでに述べたように、CLUSTERED INDEXはテーブル内のデータを物理的に並べます。
つまり、クラスター化インデックスを含むテーブルで挿入または削除を行う場合、データを変更するたびに(ほとんどの場合、FILL FACTORによって異なります)、物理テーブルを更新してソートを維持する必要があります。
比較的小さなテーブルでは問題ありませんが、GBに相当するデータが含まれているテーブルにアクセスすると、挿入や削除が並べ替えに影響し、問題が発生します。
数値の主キーなしでテーブルを作成することはほとんどありません。一意でなければならない自然キーもある場合は、それに一意のインデックスも付けます。結合は、整数のマルチカラム自然キーよりも高速です。データを変更する必要があるのは1か所のみです(自然キーは更新する必要がある傾向があり、主キーと外部キーの関係にある場合、これは悪いことです)。レプリケーションが必要な場合は、整数ではなくGUIDを使用しますが、特にJohn SmithとJohn Smithを区別するためにキーを表示する必要がある場合は、ほとんどの場合、ユーザーが読み取り可能なキーを使用します。
サロゲートキーを作成しないことがよくあるのは、多対多の関係に関与する結合テーブルがある場合です。この場合、両方のフィールドを主キーとして宣言します。
私の理解では、主キーとnull以外の制約を持つ一意のインデックスは同じです(*)。そして、仕様が明示的に述べたり暗示したりしていることに応じて、どちらか一方を選択すると思います(何を表現し、明示的に実施したいかという問題)。一意性が必要であり、nullでない場合は、主キーにします。ユニークインデックスのすべての部分がまったく発生せず、そのための要件がない場合はnullにならない場合は、ユニークインデックスにします。
残っている唯一の違いは、複数の主キーを持つことはできませんが、nullでない一意のインデックスが複数ある可能性があることです。
(*)実用的な違いを除いて、主キーは、外部キーの定義など、一部の操作のデフォルトの一意キーにすることができます。例 テーブルを参照する外部キーを定義し、列名を提供しない場合、参照されるテーブルに主キーがある場合、主キーは参照される列になります。それ以外の場合、参照される列には明示的に名前を付ける必要があります。
DBレプリケーションについて言及している他の人たちもいますが、私はそれについて知りません。
それが私次第だったら...
データベースとアプリケーションの要件を満たす必要があります。
自動インクリメントの整数またはロングID列をすべてのテーブルに追加して主キーとして機能させると、データベースの要件に対応できます。
次に、アプリケーションで使用するために、テーブルに他の一意のインデックスを少なくとも1つ追加します。これは、employee_id、account_id、customer_idなどのインデックスになります。可能であれば、このインデックスは複合インデックスであってはなりません。
複合インデックスよりもいくつかのフィールドのインデックスを個別に優先します。データベースは、where句にこれらのフィールドが含まれる場合は常に単一フィールドインデックスを使用しますが、フィールドを正確に正しい順序で指定した場合にのみ複合を使用します。つまり、指定しない限り、複合インデックスの2番目のフィールドを使用できません。 where句の最初と2番目の両方。
私はすべて計算型または関数型のインデックスを使用することに賛成です-複合インデックスではなくそれらを使用することをお勧めします。where句で同じ関数を使用すると、関数のインデックスを非常に簡単に使用できます。
これにより、アプリケーション要件が処理されます。
他の非プライマリインデックスは、実際にはそのインデックスキー値の、rowid()ではなくプライマリキー値へのマッピングである可能性が高いです。これにより、これらのインデックスを再作成することなく、物理的な並べ替え操作と削除を実行できます。