web-dev-qa-db-ja.com

テーブルのプライマリキーのベストプラクティスは何ですか?

テーブルを設計するとき、私は一意であり、主キーを作成する1つの列を持つ習慣を開発しました。これは、要件に応じて3つの方法で実現されます。

  1. 自動インクリメントするID整数列。
  2. 一意の識別子(GUID)
  3. 行識別子列として機能できる短い文字(x)または整数(または他の比較的小さな数値型)列

数値3は、かなり小さなルックアップに使用されます。ほとんどの場合、一意の静的な長さの文字列コード、または年やその他の数値などの数値を持つテーブルを読み取ります。

ほとんどの場合、他のすべてのテーブルには、自動インクリメント整数または一意の識別子の主キーがあります。

質問 :-)

私は最近、一貫した行識別子を持たず、主キーが現在さまざまな列にクラスター化されているデータベースでの作業を開始しました。いくつかの例:

  • 日時/文字
  • 日時/整数
  • datetime/varchar
  • char/nvarchar/nvarchar

これに有効なケースはありますか?これらのケースでは、常にIDまたは一意の識別子列を定義していました。

さらに、主キーをまったく持たないテーブルが多数あります。これに対する正当な理由があれば、それは何ですか?

テーブルがなぜそのまま設計されたのかを理解しようとしていますが、それは私には大きな混乱のようですが、おそらくそれには十分な理由がありました。

答えを解読するのに役立つ3番目の質問:複合プライマリキーを構成するために複数の列が使用される場合、サロゲート/人工キーに対してこの方法には特定の利点がありますか?私は主にパフォーマンス、メンテナンス、管理などに関して考えていますか?

236
Lloyd Cotten

私はいくつかのルールに従います:

  1. 主キーは必要なだけ小さくする必要があります。数値型は文字形式よりもはるかにコンパクトな形式で格納されるため、数値型を優先します。これは、ほとんどの主キーが別のテーブルの外部キーであり、複数のインデックスで使用されるためです。キーが小さいほど、インデックスが小さいほど、使用するキャッシュ内のページが少なくなります。
  2. 主キーは変更しないでください。主キーの更新は常に問題外である必要があります。これは、複数のインデックスで使用され、外部キーとして使用される可能性が最も高いためです。単一の主キーを更新すると、変更の波及効果が生じる可能性があります。
  3. 「問題の主キー」を論理モデルの主キーとして使用しないでください。たとえば、これらの「主キー」としてのパスポート番号、社会保障番号、または従業員契約番号は、現実世界の状況に合わせて変更できます。

代理キーと自然キーについては、上記の規則を参照します。自然キーが小さく、変更されない場合は、主キーとして使用できます。自然キーが大きい場合、または変更される可能性が高い場合は、代理キーを使用します。主キーがない場合、経験から、常にテーブルをスキーマに追加し、主キーを配置することを望んでいるので、代理キーを作成します。

227
Logicalmind

自然な詩の人工キーは、データベースコミュニティの間での一種の宗教的議論です。 この記事 およびそれがリンクする他のものを参照してください。私はalwaysに人工的なキーがなく、neverそれらを持っている。たとえば、次のようにケースバイケースで決定します。

  • 米国の州:テキサス州のstate_id = 1ではなく、state_code(テキサス州の「TX」など)を選択します
  • 従業員:私は通常、人工的なemployee_idを作成します。他に機能するものを見つけるのは難しいからです。 SSNまたは同等のものは機能する可能性がありますが、SSNをまだ提供していない新しい参加者などの問題がある可能性があります。
  • 従業員の給与履歴:(employee_id、start_date)。私は、not人工のemployee_salary_history_idを作成します。どのポイントに役立つか( "愚かな一貫性" 以外)

人工キーを使用する場合は常に、自然キーに対して一意の制約を常に宣言する必要があります。たとえば、必要な場合はstate_idを使用しますが、state_codeで一意の制約を宣言する方が適切です。そうしないと、最終的には次のようになります。

state_id    state_code   state_name
137         TX           Texas
...         ...          ...
249         TX           Texas
86
Tony Andrews

しばしば見落とされがちなものに対する追加コメント。代理キーを使用しないことで、子テーブルの利点が得られる場合があります。 1つのデータベース内で複数の会社を運営できる設計があるとしましょう(ホストされたソリューションなど)。

これらのテーブルと列があるとしましょう:

Company:
  CompanyId   (primary key)

CostCenter:
  CompanyId   (primary key, foreign key to Company)
  CostCentre  (primary key)

CostElement
  CompanyId   (primary key, foreign key to Company)
  CostElement (primary key)

Invoice:
  InvoiceId    (primary key)
  CompanyId    (primary key, in foreign key to CostCentre, in foreign key to CostElement)
  CostCentre   (in foreign key to CostCentre)
  CostElement  (in foreign key to CostElement)

最後のビットが意味をなさない場合、Invoice.CompanyIdは2つの外部キーの一部であり、1つはCostCentreテーブルに、もう1つはCostElementテーブルにあります。主キーは(InvoiceIdCompanyId)です。

このモデルでは、ある会社のCostElementと別の会社のCostCentreを組み合わせて参照することはできません。代理キーがCostElementおよびCostCentreテーブルで使用された場合は、そうなります。

失敗する可能性が少ないほど良い。

25
WW.

単純な理由の1つ、人為的エラーのために、自然キーの使用を避けています。自然な一意の識別子(SSN、VIN、アカウント番号など)が利用可能ですが、それらを正しく入力するには人間が必要です。 SSNを主キーとして使用している場合、データ入力中に誰かが数個の数字を転置し、エラーがすぐに検出されない場合、主キーを変更する必要があります。

私の主キーはすべてバックグラウンドでデータベースプログラムによって処理され、ユーザーはそれらを認識しません。

20
Paul

さまざまなフィールドから主キーを作成しても問題ありません。これはNatural Keyです。

(候補フィールドの一意のインデックスに関連付けられた)ID列を使用して、Surrogate Keyを作成できます。

それは古い議論です。私はほとんどの状況で代理キーを好みます。

しかし、キーがないことの言い訳はありません。

RE:EDIT

ええ、それについて多くの論争があります:D

自然なキーが自然な選択であるという事実以外に、自然なキーには明らかな利点はありません。常にName、SocialNumber-またはそのようなもの-idPersonの代わりに考えます。

代理キーは、自然キーにある問題のいくつかに対する答えです(たとえば、変更の伝播)。

サロゲートに慣れると、よりクリーンで管理しやすいように見えます。

しかし、最終的には、それは単なる好みの問題、つまり考え方の問題であることがわかります。人々は自然な鍵で「よりよく考える」が、他の人はそうではない。

13

テーブルには常に主キーが必要です。そうでない場合は、AutoIncrementフィールドである必要があります。

多くのデータを転送し、プロセスが(データベースによっては)遅くなる可能性があるため、ユーザーは主キーを省略します。しかし、その後に追加する必要があります。

リンクテーブルに関するコメント、これは正しいですが、例外ですが、整合性を保つためにフィールドはFKである必要があります。また、リンクの重複が許可されていない場合、これらのフィールドも主キーになります。 ..しかし、例外はプログラミングで頻繁に発生するものであるため、単純な形式を維持するには、データの整合性を保つために主キーが存在する必要があります。

11

これらすべての良い答えに加えて、私はちょうど読んだ良い記事を共有したいだけです偉大な主キーの議論.

いくつかのポイントを引用するだけです:

開発者は、各テーブルの主キーを選択する際にいくつかのルールを適用する必要があります。

  • 主キーは、各レコードを一意に識別する必要があります。
  • レコードの主キー値をnullにすることはできません。
  • レコードの作成時には、プライマリKey-Valueが存在する必要があります。
  • 主キーは安定したままでなければなりません。主キーフィールドは変更できません。
  • 主キーはコンパクトで、可能な限り少ない属性を含む必要があります。
  • 主キーの値は変更できません。

ナチュラルキー(に傾向がある)は規則を破ります。代理キーはルールに準拠しています。 (その記事をよく読んでください、あなたの時間の価値があります!)

8
RayLuo

主キーの特別な点は何ですか?

スキーマ内のテーブルの目的は何ですか?テーブルのキーの目的は何ですか?主キーの特別な点は何ですか?主キーに関する議論では、主キーがテーブルの一部であり、そのテーブルがスキーマの一部であるという点を見逃しているようです。テーブルとテーブルの関係に最適なものが、使用されるキーを決定するはずです。

テーブル(およびテーブルの関係)には、記録する情報に関する事実が含まれています。これらの事実は、自己完結的で、意味があり、理解しやすく、矛盾しないものでなければなりません。設計の観点から、スキーマに追加または削除された他のテーブルは、問題のテーブルに影響を与えません。情報自体にのみ関連するデータを保存する目的が必要です。テーブルに保存されている内容を理解するために、科学研究プロジェクトを実施する必要はありません。同じ目的で保存されたファクトを複数回保存することはできません。キーは、記録される情報の全体または一部であり、一意であり、プライマリキーは、テーブルへのプライマリアクセスポイントとなる特別に指定されたキーです(つまり、挿入だけでなく、データの一貫性と使用法のために選択する必要があります)パフォーマンス)。

  • ASIDE:残念ながら、アプリケーションプログラマー(私も時々)によって設計および開発されているほとんどのデータベースの副作用は、アプリケーションまたはアプリケーションフレームワークに最適なものがテーブルの主なキー選択をしばしば駆動することです。これにより、整数およびGUIDキー(これらはアプリケーションフレームワークに簡単に使用できる)およびモノリシックテーブルデザイン(これらはメモリ内のデータを表すために必要なアプリケーションフレームワークオブジェクトの数を減らす)につながります。これらのアプリケーション駆動型データベース設計の決定は、大規模に使用すると、データの一貫性に関する重大な問題につながります。この方法で設計されたアプリケーションフレームワークは、当然ながら一度にテーブルを設計します。 「部分レコード」は、時間の経過とともに入力されるテーブルとデータに作成されます。複数テーブルの相互作用が回避されるか、使用されると、アプリケーションが正しく機能しない場合にデータの一貫性が失われます。これらの設計は、意味のない(または理解しにくい)データ、テーブルに広がるデータ(現在のテーブルを理解するために他のテーブルを見る必要がある)、および複製されたデータにつながります。

主キーは必要なだけ小さくする必要があると言われていました。キーは必要なだけの大きさにすべきだと言います。無意味なフィールドをテーブルにランダムに追加することは避けてください。ランダムに追加された無意味なフィールドからキーを作成することはさらに悪いことです。特に、別のテーブルから非プライマリキーへの結合依存関係を破棄する場合はなおさらです。これは、テーブルに適切な候補キーがない場合にのみ合理的ですが、この発生は、すべてのテーブルに使用した場合、スキーマ設計が不十分であることの兆候です。

また、主キーの更新は常に問題外である必要があるため、主キーは決して変更すべきではないと言われました。ただし、更新は、削除に続いて挿入と同じです。このロジックにより、1つのキーを持つテーブルからレコードを削除してから、2番目のキーを持つ別のレコードを追加しないでください。代理主キーを追加しても、テーブル内の他のキーが存在するという事実は削除されません。テーブルの非プライマリキーを更新すると、他のテーブルが代理キーを介してその意味に依存している場合、データの意味を破壊する可能性があります(たとえば、ステータスの説明が「処理済み」から「キャンセル済み」に変更された代理キーを持つステータステーブル'間違いなくデータが破損します)。常に問題の外にあるべきなのは、データの意味を破壊することです。

これを言っても、今日のビジネスに存在する多くの貧弱に設計されたデータベース(意味のないサロゲートキー付きデータ破損-1NFの巨人)に感謝します。それは、適切なデータベース設計を理解している人々には無限の仕事があることを意味するからです。しかし、悲しいことに、それは時々私をSisyphusのように感じさせます。データベース設計に関する重要な質問については、ブログやWebサイトから離れてください。データベースを設計している場合は、CJ Dateを検索してください。 SQL ServerのCelkoを参照することもできますが、これは鼻を先に持っている場合のみです。 Oracle側では、Tom Kyteを参照してください。

7
Luke

通常、自然キーが使用可能であれば、それが最適です。したがって、datetime/char niquelyが行を識別し、両方の部分が行にとって意味がある場合、それは素晴らしいことです。

日時だけが意味を持ち、charを付加して一意にする場合は、識別フィールドを使用することもできます。

6
James Curran

私にとって自然なキーと人工的なキーは、データベースに必要なビジネスロジックの量の問題です。 社会保障番号 (SSN)は良い例です。

「私のデータベース内の各クライアントは、SSNを持っている必要があります。」 Bam、完了、それを主キーにして、完了です。ビジネスルールが変更されたときに、やけどを負ったことを覚えておいてください。

ビジネスルールを変更した経験があるため、私自身は自然なキーが好きではありません。ただし、変更されないことが確かな場合は、いくつかの重要な結合が妨げられる可能性があります。

5
Dan Williams

Steven A. Loweのロールアップされた新聞療法は、元のデータ構造の設計者に必要だと思います。

余談ですが、主キーとしての GUIDs はパフォーマンスを浪費する可能性があります。私はそれをお勧めしません。

4
Andrew Rollings

自然な主キーを探して、できる限りそれらを使用します。

自然なキーが見つからない場合、SQL Serverはツリーを使用するため、INT ++よりGUIDを使用します。ツリーの最後に常にキーを追加するのは悪いことです。

多対多のカップリングであるテーブルでは、外部キーの複合主キーを使用します。

私は幸運にもSQL Serverを使用できるので、プロファイラーとクエリアナライザーで実行計画と統計を調べ、キーのパフォーマンスを非常に簡単に調べることができます。

3
Guge

複数のフィールドで構成される「複合」または「複合」主キーを使用する必要があります。

これは完全に受け入れられる解決策です。詳細については here を参照してください。

3
adam

私も常に数値のID列を使用しています。 Oracleでは、number(18,0)をnumber(12,0)を超える本当の理由なしに使用します(または、長さではなくintになります)。 db!

また、基本的な追跡用に作成および変更された列(タイムスタンプ型)も含めます。

列の他の組み合わせに一意の制約を設定することは構いませんが、ID、作成、変更されたベースライン要件は本当に好きです。

3
JeeBee

常に自動番号またはIDフィールドを使用します。

私はプライマリキーとしてSSNを使用していたクライアントで働いていましたが、HIPAA規制により「MemberID」への変更を余儀なくされ、関連テーブルの外部キーを更新する際に多くの問題を引き起こしました。 ID列の一貫した標準に従うことは、すべてのプロジェクトで同様の問題を回避するのに役立ちました。

2
Matt

ここに、25年以上の開発経験を経て決めた経験則を示します。

  • すべてのテーブルには、自動インクリメントする単一の列主キーが必要です。
  • 更新可能にすることを目的とするビューにそれを含める
  • 主キーは、アプリケーションのコンテキストでは意味を持ちません。これは、SKU、アカウント番号、従業員ID、またはアプリケーションにとって意味のあるその他の情報であってはならないことを意味します。これは、エンティティに関連付けられた一意のキーにすぎません。

主キーは、最適化の目的でデータベースによって使用されます。特定のエンティティを特定したり、特定のエンティティに関連したりすること以外は、アプリケーションで使用しないでください。

常に単一の値の主キーを持つことで、UPSERTを非常に簡単に実行できます。

追加のインデックスを使用して、アプリケーションで意味を持つ複数列キーをサポートします。

2

GUIDs は主キーとして使用できますが、適切なタイプのGUIDを作成して、パフォーマンスを向上させる必要があります。

COMB GUIDを生成する必要があります。それとパフォーマンス統計に関する良い記事は、主キーとしてのGUIDのコストです。

また、 SQL のCOMB GUIDの構築に関するいくつかのコードはniqueidentifier vs identityarchive

1
Donny V.

すべてのテーブルshouldには主キーがあります。そうでなければ、あなたが持っているのはHEAPです-これは、状況によってはあなたが望むものかもしれません(その後、データがサービスブローカーを介して別のデータベースまたはテーブルに複製されるときの重い挿入負荷)。

行の量が少ないルックアップテーブルの場合、3 CHARコードを主キーとして使用できます。これはINTよりもスペースを取りませんが、パフォーマンスの違いはごくわずかです。それ以外では、おそらく関連テーブルの外部キーから構成される複合主キーを持つ参照テーブルがない限り、常にINTを使用します。

1
Coolcoder

この古くからの議論の前後をすべて読みたい場合は、Stack Overflowで「ナチュラルキー」を検索してください。結果のページを取得する必要があります。

1
Tom H

私は自然なキーの好みについて前もって話をします-データベース管理の生活をずっと楽にしてくれるので、可能な限りそれらを使ってください。私たちの会社では、すべてのテーブルに次の列があるという標準を確立しました。

  • 行ID(GUID)
  • 作成者(文字列。現在のユーザー名のデフォルトがあります(T-SQLではSUSER_SNAME()))
  • 作成済み(DateTime)
  • タイムスタンプ

行IDにはテーブルごとに一意のキーがあり、いずれの場合も行ごとに自動生成され(およびアクセス許可により編集が禁止されます)、すべてのテーブルおよびデータベースで一意であることが合理的に保証されます。 ORMシステムで単一のIDキーが必要な場合、これが使用されます。

一方、可能であれば、実際のP​​Kは自然な鍵です。私の内部ルールは次のようなものです:

  • 人-代理キーを使用します。 INT。内部の場合は、Active DirectoryユーザーGUIDが選択可能です
  • ルックアップテーブル(StatusCodesなど)-短いCHARコードを使用します。 INTよりも覚えやすく、多くの場合、紙のフォームとユーザーは簡潔にするためにこれを使用します(たとえば、Status = "E"は "Expired"、 "A"は "Approved"、 "NADIS"は "No Asbestos Detected"サンプルで」)
  • テーブルのリンク-FKの組み合わせ(例:EventId, AttendeeId

したがって、理想的には、自然で人間が読める、覚えやすいPK、およびORMに対応したテーブルごとの1つのIDのGUIDになります。

警告:私が管理しているデータベースは、数百万または数十億ではなく、100,000のレコードが多い傾向があるため、私のアドバイスに反するような大きなシステムの経験がある場合は、お気軽に無視してください!

0
Keith Williams

私たちは多くの結合を行い、複合主キーはパフォーマンスを独占するようになりました。単純なintまたはlongは、2番目の候補キーを導入している場合でも多くの問題を処理しますが、3つのフィールドよりも1つのフィールドに参加する方がはるかに簡単で理解しやすいです。

0
Dan Blair