複合主キーは悪い習慣ですか?[閉まっている]


14

複合主キーが悪い習慣であるかどうかを知り、そうでない場合は、どのシナリオを使用することが推奨されますか。

私の質問はこの記事に基づいています

データベースの設計ミス

複合主キーに関する部分:

悪い実践No. 6:複合主キー

現在、多くのデータベース設計者は、2つ以上のフィールドの組み合わせで定義された複合フィールドではなく、整数IDの自動生成フィールドを主キーとして使用することについて話しているため、これは論争の種です。これは現在「ベストプラクティス」として定義されており、個人的には同意する傾向があります。

複合主キーの画像

ただし、これは単なる慣例であり、もちろん、DBEでは複合主キーを定義できます。これは、多くの設計者が避けられないと考えています。したがって、冗長性と同様に、複合主キーは設計上の決定事項です。

ただし、複合主キーを持つテーブルに数百万の行が含まれることが予想される場合、複合キーを制御するインデックスが、CRUD操作のパフォーマンスが非常に低下するところまで大きくなる可能性があることに注意してください。その場合、インデックスが十分にコンパクトで、一意性を維持するために必要なDBE制約を確立する単純な整数ID主キーを使用する方がはるかに優れています。


4
これは「良い」または「悪い」習慣ではありません。すべての設計決定は目的を果たす必要があります。複合PKが必要な理由を(自分自身と他の人に)説明できる場合は、問題ありません。逆に、なぜそれが必要ないのかを説明できれば、それでも問題ありません。あなたがリンクしている記事は、私の見解では、説明が非常に貧弱です。
mustaccio 2017年

この記事は重要な点を示していますが、「ベストプラクティス」で人気のあるフレームワーク(たとえば、railsなど)を見ると、このタイプの主キーはサポートされていないので、理由を尋ねました。それは技術的な問題や何かのためのものです。
ハックバン2017年

フレームワークの設計では、「単純な」単一列の整数主キーをサポートする方が簡単です。また、ほとんどの開発者(少なくとも私の個人的な経験では)は(少なくともこのサイトのユーザーに比べて)データベースのスキルに関してあまり能力がないため、ソフトウェアのほとんどのユーザーにとって十分に機能します。ソフトウェアのほとんどのユーザーは複合キーを必要としない(または、少なくとも最初は必要とは思わない)ので、複合キーの(適切な)サポートを提供しなくても問題はありません。
ウィレムレンゼマ2017年

1
GUIDはINTEGERよりも優れています[シリアル| Auto_Increment | アイデンティティ| <whatever_integer_you_like>]?
Vérace

4
私はその作家を雇わないだろう
パパラッツォ

回答:


31

の使用"Composite keys as PRIMARY KEY is bad practice"はまったくナンセンスだと言うには!

コンポジットPRIMARY KEYは多くの場合非常に「良いこと」であり、日常生活で発生する自然な状況をモデル化する唯一の方法です。

古典的なDatabases-101の学生とコースの教育例、および多くの学生が講じた多くのコースを考えてみてください。

テーブルコースと学生を作成します。

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

PostgreSQL方言(およびMySQL)の例を紹介します。少し調整を加えたサーバーであれば問題なく機能するはずです。

さて、あなたは明らかにどの学生がどのコースを取っているかを追跡したいので-と呼ばれるものjoining table(またはlinkingmany-to-manyまたはm-to-nテーブルとも呼ばれます)があります。彼らはまたassociative entities、より専門的な専門用語で知られています!

1つのコースは多くの学生を持つことができます。
1人の学生が多くのコースを受講できます。

したがって、結合テーブルを作成します

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

さて、この表を賢明に与える唯一の方法PRIMARY KEYは、それKEYをコースと学生の組み合わせにすることです。そのようにすると、以下を取得できません。

  • 学生とコースの組み合わせの複製

    • コースは同じ学生を1回のみ登録できます。

    • 学生は同じコースに1回のみ登録できます

  • また、KEY学生ごとのコースの既製の検索もあります

  • 学生のいないコースや、コースを履修していない学生を見つけるのは簡単です。

    -db-fiddleの例では、PK制約がCREATE TABLEに組み込まれています-どちらの方法でも実行できます。私はすべてをCREATE TABLEステートメントに含めることを好みます。


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

これで、コースによる学生の検索が遅いことがUNIQUE INDEXわかった場合は、on(sc_student_id、sc_course_id)を使用できます。

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

ありません何のインデックスを追加するための特効薬は-彼らがします作るINSERT秒とUPDATE遅くだが、非常に大きな利点で減少SELECT回!知識と経験を踏まえてインデックスを作成するかどうかは開発者次第ですが、コンポジットPRIMARY KEY常に悪いと言うのは間違いです。

テーブルを結合する場合、それらは通常、意味のある唯一の PRIMARY KEYものです!テーブルを結合することは、ビジネスや自然、または私が考えることができるほぼすべての領域で何が起こるかをモデル化する唯一の方法でもあります。

このPKは、covering index検索の高速化に役立つとしても使用されます。この場合、(course_id、student_id)を定期的に検索していると特に便利です。

これは、コンポジットPRIMARY KEYが非常に優れたアイデアであり、現実をモデル化する唯一の健全な方法のほんの一例です!私の頭の上から、私はもっと多くのことを考えることができます。

私自身の作品の例!

flight_id、出発空港と到着空港のリスト、および関連する時刻が含まれているフライトテーブルを検討してください。さらに、搭乗員がいるcabin_crewテーブルも検討してください。

唯一これをモデル化することができる健全な方法はattibutesとしてflight_idとcrew_idでflight_crewテーブルを持つことであり、唯一の正気は、PRIMARY KEY二つのフィールドの複合キーを使用することです!


2
コースと学生の例では、course_studentにid主キーと一意のインデックスがcs_student_id cs_course_idあり、同じ結果が得られる可能性がありますか?
ハックバン2017年

2
なぜそれを行うリソースを無駄にするのですか?PK(course_id、student_id)を使用すると、定義により、これらのフィールドに既に一意のインデックスがあります!(student_id、course_id)の一意のインデックスは、検索の高速化に役立つ可能性があります。たとえば、コースを受講していない学生を探している場合、その決定は運用上のものになる可能性がありますが、最近の比較的安価なストレージでは、特に、テーブルが頻繁に更新されることはないと思われるので、私はそれを推奨します。
Vérace

1
リンクテーブルについては完全に同意します。現在、いくつかのテーブルで作業しています。ただし、C#の帽子をかぶったときは、reversepocoジェネレーターを使用して、次のレイヤーのために有用なクラス(検索、保存など)を構築しています。私は大きな問題にぶつかりました-複合キーは、一般的な保存/検索コードを持つためのPITAになります。はい、多分EDMXファイルに戻ることができるかもしれませんが、それでも特別なケースコード(Pkey列をカウントしますか?)を回避するか、人工代理キーを追加する必要があります(一意性制約を追加しないでください:()。したがって、私は推測します。コンポジットを好まない人々がアプリレイヤーコードから話しています
Richard Griffiths

挿入の頻度とインデックスデフラグの頻度とメンテナンスウィンドウの頻度に応じて、これはより良いソリューションです。しかし、一部の設計の選択は、すぐには見えない可能性がある要件によって引き起こされる妥協です。しかし、1つのコメントが言ったように、両方のシナリオの長所/短所を特定し、設計の選択を行います。
Jonathan Fite、

学生がコースを繰り返すとどうなりますか?次に、時間的に分離されたコースが異なるIDを取得しない限り、さらに別のマッピングテーブルが作成されます。または、キーに追加する必要があるコース日付のフィールドを追加します。
iheanyi

3

中途半端な考え方:「主キー」は、テーブル内のデータを検索するために使用される唯一の一意のキーである必要はありませんが、データ管理ツールがデフォルトの選択として提供します。したがって、2つの列の複合か、ランダム(おそらくシリアル)に生成された数値をテーブルキーとして使用するかを選択するには、2つの異なるキーを同時に使用できます。

データ値に行を表すことができる適切な一意の用語が含まれている場合は、「合成」キーを使用するよりも、複合であっても「主キー」として宣言するほうがよいでしょう。合成キーは技術的な理由でパフォーマンスが向上する可能性がありますが、サービスを機能させるために他の方法を実行する必要がない限り、実際の用語を主キーとして指定して使用することが私のデフォルトの選択です。

Microsoft SQL Serverには、インデックス順にデータの物理ストレージを制御する「クラスター化インデックス」の明確だが関連する機能があり、他のインデックス内でも使用されます。既定では、主キーはクラスター化インデックスとして作成されますが、できればクラスター化インデックスを作成した後で、代わりに非クラスター化を選択できます。したがって、整数のIDで生成された列をクラスター化インデックスとして、たとえばファイル名nvarchar(128文字)を主キーとして持つことができます。ファイル名を外部キーの用語として他のテーブルに格納した場合でも、クラスター化インデックスキーは狭いため、これはより良い場合があります。

設計に、関連するデータを識別するための不便な主キーを含むデータのテーブルのインポートが含まれている場合は、ほとんどそれで行き詰まっています。

https://www.techopedia.com/definition/5547/primary-keyは、すべてのデータテーブルで顧客の社会保障番号を顧客キーとしてデータを保存するか、または任意のcustomer_idを生成するかを選択する例を説明していますそれらを登録します。実際、SSNが機能するかどうかは別として、これはSSNの重大な悪用です。これは個人的な機密データの価値です。

したがって、現実の事実をキーとして使用する利点は、「Customer」テーブルに再度参加しなくても、他のテーブルでそれらに関する情報を取得できることですが、これはデータセキュリティの問題でもあります。

また、SSNまたはその他のデータキーが誤って記録されていると問題が発生するため、「顧客」のみではなく、20の制約付きテーブルに誤った値が含まれています。一方、合成のcustomer_idには外部的な意味がないため、間違った値になることはありません。


1
特に、顧客データをキーとすることにより、既知の一意の顧客データ(ここではSSN)でさえ、そのデータを修正する必要がある場合は機能しなくなるという観測結果に感謝します。
ToolmakerSteve
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.