13

7年間の開発経験で見たすべてのデータベースのほぼすべてのテーブルには、自動インクリメントの主キーがあります。どうしてこれなの?米国の州の表があり、各州が一意の名前を持っている必要がある場合、自動インクリメントの主キーはどのように使用されますか?州名を主キーとして使用しないのはなぜですか?一意の行を装った複製を許可する言い訳のように私には思えます。

これは私には明白に思えますが、繰り返しになりますが、他の誰も私と同じ論理的結論に到達して行動しているようには見えないので、私が間違っている可能性が高いと想定する必要があります。

自動インクリメントキーを使用する必要がある実際の実用的な理由はありますか?

4

9 に答える 9

21

この質問はSOで何度も聞かれ、開発者とDBAの間(および開発者の間)で長年にわたって多くの議論の対象となってきました。

まず、あなたの質問の前提は、一方のアプローチがもう一方のアプローチよりも普遍的に優れていることを意味しているということから始めましょう...これは実際の生活ではめったにありません。代理キーと自然キーにはどちらにも用途と課題があります。それらが何であるかを理解することが重要です。システムでどちらを選択する場合でも、一貫性には利点があることに注意してください。これにより、データモデルが理解しやすくなり、クエリやアプリケーションの開発が容易になります。また、PKの場合、自然キーよりも代理キーを好む傾向があると言いたいのですが、それは、自然キーがその役割で役立つことがない場合があるという意味ではありません。

サロゲートキーと自然キーは相互に排他的ではなく、多くの場合、相互に補完できることを理解することが重要です。データベーステーブルの「キー」は、単にレコード(行)を一意に識別するものであることに注意してください。1つの行に、レコードを一意にするさまざまなカテゴリの制約を表す複数のキーを含めることは完全に可能です。

一方、主キーは、データベースが参照整合性を適用し、他のテーブルで外部キーを表すために使用する特定の一意のキーです。どのテーブルにも1つの主キーしか存在できません。主キーの本質的な品質は、100%一意であり、NULLではないことです。主キーの望ましい品質は、それが安定している(変わらない)ことです。変更可能な主キーは可能ですが、データベースに多くの問題を引き起こし、回避する方が適切です(カスケード更新、RI障害など)。テーブルに代理主キーを使用することを選択した場合は、自然キーの存在を反映するために一意の制約を作成することも検討する必要があります。

代理キーは、次の場合に役立ちます。

  1. 自然キーは安定していません(値は時間の経過とともに変化する可能性があります)
  2. 自然キーが大きいか扱いにくい(複数の列または長い値)
  3. 自然キーは時間の経過とともに変化する可能性があります(時間の経過とともに列が追加/削除されます)

すべての行に短く安定した一意の値を提供することで、データベースのサイズを縮小し、パフォーマンスを向上させ、外部キーを格納する依存テーブルの変動性を減らすことができます。キーポリモーフィズムの利点もありますが、これについては後で説明します。

場合によっては、テーブル間の関係を表現するために自然キーを使用すると問題が発生する可能性があります。たとえば、自然キーがであるPERSONテーブルがあるとします{LAST_NAME, FIRST_NAME, SSN}。Proposer、Reviewer、Approver、およびAuthorizerへの参照を格納する必要がある他のテーブルGRANT_PROPOSALがある場合はどうなりますか。この情報を表現するには、12列が必要です。また、どの列がどの種類の個人に属しているかを識別するために、ある種の命名規則を考え出す必要があります。しかし、PERSONテーブルが自然キーに6、8、または24列を必要とした場合はどうなるでしょうか。これは急速に管理不能になります。代理キーは、キーのセマンティクス(意味)を識別子としての使用から切り離すことにより、このような問題を解決します

質問で説明した例も見てみましょう。

状態の2文字の省略形を、その​​テーブルの主キーとして使用する必要があります。

表面的には、省略形フィールドが適切な主キーの要件を満たしているように見えます。比較的短く、外部キーとして伝播しやすく、安定しているように見えます。残念ながら、あなたは一連の略語を管理していません...郵便局は管理しています。そして、ここに興味深い事実があります。1973年、USPSは、カナダのニューブランズウィックとの混乱を最小限に抑えるために、ネブラスカの略語をNBからNEに変更しました。この話の教訓は、自然キーはデータベースの制御外にあることが多く、時間の経過とともに変化する可能性があるということです。できないと思っても。この問題は、人や製品などのより複雑なデータではさらに顕著になります。ビジネスが進化するにつれて、そのようなエンティティを一意にするものの定義が変わる可能性があります。そして、これはデータモデラーやアプリケーション開発者にとって重大な問題を引き起こす可能性があります。

先ほど、主キーがキーのポリモーフィズムをサポートできることを説明しました。どういう意味ですか?さて、ポリモーフィズムとは、あるタイプAが、別のタイプBのように見え、そのように使用される能力のことです。データベースでは、この概念は、さまざまなクラスのエンティティのキ​​ーを1つのテーブルに結合する機能を指します。例を見てみましょう。どのエンティティがどのユーザーによってどの日付に変更されたかを識別する監査証跡をシステムに持たせたいと想像してみてください。次のフィールドを使用してテーブルを作成すると便利です{ENTITY_ID, USER_ID, EDIT_DATE}。残念ながら、自然キーを使用すると、エンティティごとにキーが異なります。したがって、別のリンクテーブルを作成する必要がありますエンティティの種類ごとに...そして、さまざまな種類のエンティティとそれらのキーがどのように形成されるかを理解する方法でアプリケーションを構築します。

誤解しないでください。私は、代理キーを常に使用する必要があると主張しているわけではありません。現実の世界では、決して、これまで、そして常に採用するのは危険な立場です。代理キーの最大の欠点の1つは、多くの「意味のない」数値で構成される外部キーを持つテーブルが作成される可能性があることです。これにより、全体像を取得するために他のテーブルからレコードを結合または検索する必要があるため、レコードの意味を解釈するのが面倒になる可能性があります。また、サーバー間で一意の増分番号を割り当てることが常に可能であるとは限らないため、分散データベースの展開がより複雑になる可能性があります(ただし、OracleやSQLServerなどの最新のデータベースはシーケンスレプリケーションによってこれを軽減します)。

于 2010-10-13T22:03:23.077 に答える
17

いいえ。

ほとんどの場合、代理INT IDENTITYキーを使用するのは簡単なオプションです。NULLではなく100%一意であることが保証されます。これは、多くの「自然」キーでは提供されないものです。名前は変更される可能性があり、SSNやその他のアイテムも変更される可能性があります。情報。

州の略語と名前の場合、どちらかといえば、2文字の州の略語をキーとして使用します。

主キーは次のようにする必要があります

  • ユニーク(100%保証!「ほぼ」ユニークだけではありません)
  • NULL以外

主キーは次のようになります。

  • 可能な限り安定している(変更しない-または少なくともあまり頻繁ではない)

州の2文字のコードは間違いなくこれを提供します-それは自然キーの候補かもしれません。キーも小さくする必要があります。4バイトのINTは完璧で、2文字のCHAR(2)列はまったく同じです。VARCHAR(100)フィールドなどをキーとして使用することは決してありません。これはあまりにも不格好で、常に変更される可能性がありますが、適切なキー候補ではありません。

したがって、自動インクリメントの「人工」(代理)主キーを用意する必要はありませんが、自然に発生するデータは実際には主キーになるタスクに依存しないため、多くの場合、これは非常に良い選択です。いくつかの列を持つ巨大な主キーを持つことは避けてください-それらはあまりにも不格好で非効率的です。

于 2010-10-13T21:23:28.257 に答える
3

「Primary」キーというフレーズでの「Primary」という単語の使用は、本当の意味で誤解を招くものだと思います。

まず、「キー」はテーブル内で一意である必要がある属性または属性のセットであるという定義を使用します。

次に、キーを持つことは、しばしば相互に矛盾するいくつかの目的に役立ちます。

目的1.この親テーブルと関係のある子テーブルの1つまたは複数のレコードへの結合条件として使用します。(これらの子テーブルで明示的または暗黙的に外部キーを定義します)
目的2.(関連)子レコードが親テーブルに親レコードを持っている必要があることを確認します(子テーブルFKは親テーブルにキーとして存在する必要があります)
目的3。テーブル内の特定のレコード/行を迅速に見つける必要があるクエリのパフォーマンスを向上させるため。

目的4。(データの一貫性の観点から最も重要です!)同じ論理エンティティを表す重複行がテーブルに挿入されないようにすることで、データの一貫性を確保します。(これは「自然」キーと呼ばれることが多く、比較的不変のテーブル(エンティティ)属性で構成されている必要があります。)

明らかに、意味のない、自然でないキー(GUIDや自動生成された整数など)は、目的4を満たすことがまったくできません。

しかし、多くの(ほとんどの)テーブルでは、#4を提供できる完全に自然キーは、多くの場合、複数の属性で構成され、幅が広すぎるか、幅が広すぎるため、#1、#2、または#3の目的で使用すると許容できなくなります。パフォーマンスへの影響。

答えは簡単です。両方を使う。他の子テーブルのすべての結合とFKに単純な自動生成積分キーを使用しますが、データの一貫性を必要とするすべてのテーブル(非常に少数のテーブルにはない)に、一貫性のないデータ行の挿入を防ぐ代替の自然一意キーがあることを確認してください。 ..さらに、常に両方を持っている場合、自然キーを使用することに対するすべての異議(変更された場合はどうなりますか?FKとして参照されるすべての場所を変更する必要があります)は、そのために使用していないため、議論の余地があります。 ..データの重複を避けるために、PKである1つのテーブルでのみ使用しています。

両方なしで逃げることができるのは、他のテーブルとの関係に関与せず、明白で信頼できる自然キーを持つ完全にスタンドアロンのテーブルの場合のみです。

于 2010-10-13T21:35:18.077 に答える
2

一般に、数値の主キーは文字列よりもパフォーマンスが優れています。さらに、一意のキーを作成して、重複が忍び寄るのを防ぐことができます。これにより、重複がないことが保証されますが、数値のパフォーマンス(シナリオの文字列との比較)も得られます。

ほとんどの場合、主要なデータベースには、文字列ベースの主キーには存在しない整数ベースの主キーのパフォーマンスが最適化されています。しかし、それは合理的な推測にすぎません。

于 2010-10-13T21:22:18.373 に答える
1

はい、私の意見では、すべてのテーブルに自動インクリメント整数キーが必要です。これにより、JOINと(特に)フロントエンドプログラミングの両方がはるかに簡単になります。他の人は違った感じがしますが、これは20年以上の話の経験です。

唯一の例外は、短い(4文字または5文字の)TEXTコード値に置き換えても構わないと思っている小さな「コード」または「ルックアップ」テーブルです。これを行うのは、データベースでこれらを頻繁に使用し、ルックアップテーブルで説明を検索したり、結果セットに結合したりしなくても、ユーザーに意味のある表示を表示できるためです。Statesテーブルの例は、このカテゴリに当てはまります。

于 2010-10-13T21:29:15.110 に答える
1

いいえ、絶対にありません。

変更できない主キーを持つことは良い考えです(UPDATEは主キー列に対して有効ですが、一般的に混乱を招く可能性があり、子行に問題を引き起こす可能性があります)。ただし、アプリケーションに自動インクリメント値よりも適した他の候補がある場合は、代わりにそれを使用する必要があります。

パフォーマンス面では、一般に、列が少ないほど優れており、特にインデックスが少なくなります。一意のインデックスがあり、ビジネスプロセスで変更できない別の列がある場合は、それが適切な主キーである可能性があります。

MySQL(Innodb)の観点から言えば、InnoDBは常に主キーをクラスター化し、それをセカンダリインデックスに含めるため、「人工」列ではなく「実際の」列を主キーとして使用することもお勧めします(これが方法です)それらの行を検索します)。これにより、他の一意のインデックスでは不可能な主キーを使用して、有用な最適化を実行できる可能性があります。MSSQLユーザーは、主キーをクラスター化することを選択することがよくありますが、別の一意のインデックスをクラスター化することもできます。

編集:

ただし、データベースが小さく、パフォーマンスやサイズをあまり気にしない場合は、不要な自動インクリメント列を追加してもそれほど悪くはありません。

非自動インクリメント値(たとえば、UUID、または独自のアルゴリズムに従って生成された他の文字列)は、一貫した自動インクリメントIDを維持することが難しい(または不可能な-分散型と考える)分散型、シャーディング型、または多様なシステムに役立つ場合がありますネットワークパーティションの両側に行を挿入し続けるシステム)。

于 2010-10-13T21:30:08.510 に答える
1

自動インクリメントキーが時々使用される理由を説明するかもしれない2つのことがあると思います:

  • スペースの考慮; 州名はそれほど多くはありませんが、必要なスペースが増える可能性があります。名前を主キーとして状態を保存したい場合は、先に進んでください。ただし、より多くの場所で実行されます。場合によっては問題ないかもしれませんし、昔の問題のように聞こえますが、習慣は根付いているのかもしれません。そして、私たちプログラマーとDBAは習慣が大好きです:D

  • 防御上の考慮事項:私は最近、次の問題を抱えていました。データベースには、電子メールがすべての識別の鍵となるユーザーがいます。メールをプロマリーキーにしてみませんか?突然の境界の場合を除いて、1人の男が2つの異なるアドレスを持つために2回そこにいなければならず、誰も仕様でそれについて話していなかったため、アドレスは正規化されません。この状況では、2つの異なる電子メールが同じ人とを指している必要があります。 ..しばらくすると、髪の毛を抜くのをやめて、いまいましい整数ID列を追加します

私はそれが悪い習慣でも良い習慣でもないと言っているのではありません。合理的な主キーを中心に優れたシステムを設計できると確信していますが、これらの2つのポイントから、恐怖と習慣が原因の2つであると私は信じています。

于 2010-10-13T21:30:31.520 に答える
0

これは、リレーショナルデータベースの重要なコンポーネントです。状態名全体ではなく整数を状態に関連付けると、データベースのスペースを大幅に節約できます。状態テーブルを参照する100万件のレコードがあるとします。これらの各レコードの数値に4バイトを使用しますか、それとも各州名にバイト全体を使用しますか?

于 2010-10-13T21:23:42.520 に答える
0

ここにいくつかの実際的な考慮事項があります。

最新のORM(rails、django、hibernateなど)のほとんどは、主キーとして単一の整数列がある場合に最適に機能します。

さらに、標準の命名規則(たとえば、主キーとしてのidと外部キーとしてのtable_name_id)を使用すると、キーの識別が容易になります。

于 2010-10-13T23:08:04.577 に答える