web-dev-qa-db-ja.com

複合主キー:良いか悪いか

オンラインストアシステム用のデータベースを設計しています。 このウェブサイトのいくつかの投稿を読んで出会ったという質問は、以下で説明する場合に複合主キーを使用できますが、それは本当に悪い習慣ですか?この点で私が読んだstackoveflowの投稿は、多くの人がそれが悪い習慣だと言っているので、私は尋ねています)。

注文に対する支払いを別のテーブルに保存したい。その理由は、注文には多対多の関係の形で別のテーブルで処理される多くのアイテムを含めることができるためです。支払いテーブルに複合主キーを使用しないと、一意のPaymentIDが失われます。

[PaymentId] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[OrderId] INT NOT NULL PRIMARY KEY --Also a Foreign Key--

ここで、OrderIdの主キーを削除すると、ここで1対1の関係が失われるので、Many OrderIds can be associated to many PaymentIds、これは必要ありません。

これが以前の質問複合キーが悪い考えであると結論付けた理由です。だから私は自分自身でこれを明確にしたい。それが悪い場合、ベストプラクティスは何ですか?

42
JAX

複合主キーが悪いという結論はありません。

ベストプラクティスは、some列または行を一意に識別する列を持つことです。ただし、一部のテーブルでは、単一の列だけでは行を一意に識別するのに十分ではありません。

SQL(およびリレーショナルモデル)では、複合主キーを使用できます。いくつかのケースでは良い習慣です。または、別の見方をすれば、それはすべての場合において悪い習慣ではないということです。

一部の人々は、everyテーブルには、一意の値を自動的に生成し、主キーとして機能する整数列が必要であると考えています。一部の人々は、この主キー列は常にidと呼ばれるべきだと主張しています。しかし、それらは慣習であり、必ずしもベストプラクティスではありません。特定の決定を簡素化するため、コンベンションにはいくつかの利点があります。しかし、慣習にも制限があります。

一部の人々が layaway を購入するか、複数の支払い元(たとえば、2枚のクレジットカード)を持っているか、2人の異なる人々が1株の支払いを希望しているため、複数の支払いがある注文があります注文(私は頻繁に友人と一緒にレストランに行き、私たちはそれぞれ自分の食事の代金を支払うので、スタッフは各クレジットカードで注文の半分を処理します)。

あなたが説明するシステムを次のように設計します。

Products  : product_id (PK)

Orders    : order_id (PK)

LineItems : product_id is (FK) to Products
            order_id is (FK) to Orders
            (product_id, order_id) is (PK)

Payments  : order_id (FK)
            payment_id - ordinal for each order_id
            (order_id, payment_id) is (PK)

これは、 関係を識別する の概念にも関連しています。注文が存在するためだけに支払いが存在すると定義されている場合は、注文を主キーの一部にします。

LineItemsテーブルには、自動インクリメントの単一列のプライマリキーもありません。多対多のテーブルは、複合主キーを適切に使用する典型的な例です。

45
Bill Karwin

この質問は、宗教戦争を生む可能性がある意見を求めることに危険なほど近い。私のテーブルに自動増加する整数主キー(TablenameIdではなくIdのようなもの)を持つことに非常に偏っている人として、それがオプションである1つの状況があります。

他の回答では、主キーが必要な理由を説明していると思います。

非常に重要な理由の1つは、参照のためです。リレーショナルデータベースでは、理論上、任意のエンティティを外部キー関係を介して別のエンティティから参照できます。外部キーの場合、必ず1つの列で行を一意に定義する必要があります。それ以外の場合は、互いに整列する異なるテーブルの複数の列を処理する必要があります。これは可能ですが、面倒です。

参照しているテーブルは「エンティティ」テーブルではなく、「ジャンクション」テーブルです。多対多の関係を処理するためのリレーショナルデータベース構造です。それは実際にはエンティティを表していないため、外部キー関係を持つべきではありません。したがって、複合主キーは合理的です。データベースのサイズが心配な場合など、人為的な主キーを省くことが望ましい状況もあります。

19
Gordon Linoff

ディスク領域は安価であるため、慣例に従って命名されたint identity(1,1)にクラスター化された主キー(pk +テーブル名など)をお勧めします。クエリ、結合、インデックス、その他の制約を管理しやすくします。

ただし、それを行わない正当な理由が1つあります(少なくともMS SQL Serverでは)。基盤となるストレージシステムでデータの物理的な並べ替えを管理する場合。

クラスター化された主キーが物理的なソート順を決定します。 ID列で行う場合、物理的なソート順は基本的に挿入順です。ただし、特に同じ方法でテーブルをクエリする場合は特に、これは最適ではない場合があります。非常に大きなテーブルでは、適切な物理的な並べ替え順序を取得すると、クエリが非常に高速になります。たとえば、2つの列の複合でクラスター化インデックスが必要な場合があります。

7
JeromeE

ベストプラクティスは最善の場合に役立ちますが、最悪の場合は盲目になります。ベストプラクティスに反することは罪ではありません。どんなトレードオフをしているのかを知っておいてください。

データベースエンジンは非常に複雑なものになる可能性があります。特定のエンジンによってどのような最適化が行われているのかがわからなければ、どの種類のコンストラクトが最高のパフォーマンスをもたらすかを判断するのは困難です(ここで話している問題はパフォーマンスだと思います)。複合キーは、ある種類のデータベースの大きなテーブルでは問題がありますが、別の種類では目立った影響はありません。

私が学んだ便利な方法は、アプリケーションをできるだけシンプルにするように常に努力することです。複合キーを使用すると、挿入前にルックアップを実行したり、他の迷惑をかけたりする必要がなくなりますか?それらを使用します。ただし、これらを使用すると、アプリケーションが重要なパフォーマンス要件を満たさなくなることに気付いた場合は、それらを使用しないソリューションを検討してください。

5
Emanuel