92

私のチームでの活発な議論の中で、ほとんどの人が主キーとして好むものを考えさせられました。次のグループがありました-

  1. 自動インクリメントが十分な主キーである Int/ BigInt 。
  2. 主キーを構成する列は少なくとも 3 つ必要です。
  3. Id、GUID、および人間が判読できる行識別子はすべて、異なる方法で処理する必要があります。

PK の最適なアプローチは何ですか? あなたの意見を正当化できれば素晴らしいことです。上記よりも良いアプローチはありますか?

編集: 適切にスケーリングされる行の人間が読める識別子を生成するための簡単なサンプル/アルゴリズムを持っている人はいますか?

4

26 に答える 26

86

ときどき接続されるアプリを使用してデータベース間で同期を行う場合は、主キーに GUID を使用する必要があります。デバッグにはちょっと面倒なので、それ以外は自動インクリメントする int に固執する傾向があります。

自動インクリメント int はデフォルトである必要があり、それらを使用しないことは正当化されるべきです。

于 2008-12-31T21:21:47.590 に答える
58

本当に基本的な点、つまり、主キーは、同じ現実世界のエンティティのテーブルに2つのエントリを取得しないことを保証するものであるということを(私が考えるものとして)指摘する答えは見当たりません(データベースでモデル化されます)。この観察は、主キーの良い選択と悪い選択を確立するのに役立ちます。

たとえば、(米国の) 州名とコードのテーブルでは、名前またはコードのいずれかが主キーになる可能性があります。これらは 2 つの異なる候補キーを構成し、そのうちの 1 つ (通常は短い方 - コード) が主キーとして選択されます。主キー。機能依存性 (および結合依存性 - 1NF から 5NF) の理論では、重要なのは主キーではなく候補キーです。

反例として、人間の名前は通常、主キーとして不適切な選択をします。「ジョン・スミス」やそれに似た名前で通う人はたくさんいます。ミドル ネームを考慮に入れても (覚えておいてください: 誰もがミドル ネームを持っているわけではありません。たとえば、私は持っていません)、重複の可能性は十分にあります。したがって、人々は名前を主キーとして使用しません。彼らは、社会保障番号 (SSN) や従業員番号などの人工キーを発明し、それらを使用して個人を指定します。

理想的な主キーは、短く、一意で、覚えやすく、自然なものです。これらの特性のうち、一意性は必須です。残りは、現実世界のデータの制約を考慮して変更する必要があります。

したがって、特定のテーブルの主キーを決定するには、そのテーブルが何を表しているかを調べる必要があります。テーブル内の各行を一意に識別するテーブル内の列値のセットはどれですか? それらは候補キーです。ここで、各候補キーが 4 列または 5 列で構成されている場合、(主に短さの理由で) 適切な主キーを作成するにはそれらが不格好すぎると判断する可能性があります。そのような状況では、人工的に生成された番号である代理キーを導入することがあります。非常に多くの場合 (ただし常にではありません)、代理キーには単純な 32 ビット整数で十分です。次に、この代理キーを主キーとして指定します。

ただし、他の候補キー (代理キーも候補キーであり、選択された主キーであるため) がすべて一意の識別子として維持されるようにする必要があります。通常は、これらの列のセットに一意の制約を設定します

行が一意である理由を特定するのが難しい場合がありますが、単に情報を繰り返すだけではそれが真実でなくなるため、それを行う方法が必要です。注意を怠り、同じ情報を格納していると称する 2 つ (またはそれ以上) の行を取得し、その情報を更新する必要がある場合、(特にカーソルを使用している場合) 1 つの行だけを更新する危険があります。すべての行ではなく、行が同期していないため、どの行に正しい情報が含まれているか誰もわかりません。

これは、いくつかの点でかなり強硬な見方です。

必要なときに GUID を使用することに特に問題はありませんが、GUID は大きくなる傾向があり(16 ~ 64 バイト)、頻繁に使用されます。非常に多くの場合、完全に適切な 4 バイト値で十分です。4 バイトの値で十分な GUID を使用すると、ディスク領域が無駄になり、インデックス ページごとの値が少なくなるため、インデックス付きのデータへのアクセスも遅くなります。情報。

于 2009-01-01T03:09:08.590 に答える
27

人々は普遍的な正解を求めているため、これは単なる宗教上の問題です。あなたのチームとこの SO スレッドの両方が非常に多くの意見の相違を示しているという事実は、さまざまな状況で、説明したすべてのソリューションを使用する十分な理由があるという手がかりになるはずです。

  • 代理キーは、行を一意に識別するのに適した属性または属性セットがテーブル内にない場合に役立ちます。
  • テーブルを人間が読みやすいものにするために、可能な場合は自然キーを使用することをお勧めします。自然キーを使用すると、従属テーブルの外部キーにサロゲート ID の代わりに実際の値を含めることもできます。stateたとえば、 (CA、TX、NY)を格納する必要がある場合char(2)は、int の代わりに自然キーを使用することもできます。
  • 必要に応じて複合主キーを使用します。id完全に適切な複合キーが存在する場合は、不必要に" " 代理キーを追加しないでください(これは多対多のテーブルで特に当てはまります)。すべてのテーブルに 3 列のキーを配置するという義務は、まったくナンセンスです。
  • GUID は、複数のサイトで一意性を維持する必要がある場合のソリューションです。主キーの値が一意である必要があるが、順序付けや連続性が必要ない場合にも便利です。
  • INT vs. BIGINT: テーブルで主キーに 64 ビットの範囲が必要になることは一般的ではありませんが、64 ビット ハードウェアの可用性が高まるにつれて、それが負担になることはなく、オーバーフローしないことがより保証されます。INTはもちろん小さいので、スペースが限られている場合はわずかな利点があります.
于 2008-12-31T22:01:42.843 に答える
20

この種の情報源として、The Database Programmer ブログが気に入っています。

主キーに 3 列? ビジネス ルールの要求に応じて、列には適切な一意の制約が必要であると言えますが、それでも別の代理キーが必要です。複合キーとは、ビジネス ロジックがキーに入るという意味です。ロジックが変更されると、スキーマ全体が台無しになります。

于 2008-12-31T21:23:02.050 に答える
15

私は私のユニークなものが好きです。

于 2009-01-06T12:14:40.643 に答える
11

ちょっと話が逸れましたが、共感したくなりました...

主キーが GUID の場合は、クラスター化インデックスにしないでください。GUID はシーケンシャルではないため、データはほとんどすべての挿入時にディスク上で再配置されます。(うん。) GUID を主キーとして使用する場合は、非クラスター化インデックスにする必要があります。

于 2009-01-03T03:23:53.573 に答える
10

私は常に代理キーを使用します。代理キー (通常は ID 列、自動インクリメント、または GUID) は、キーがデータ自体に存在しないものです。一方、自然キーは、それ自体で行を一意に識別するキーです。私が人生で言える限り、本当の自然キーはほとんどありません。米国の SSN のようなものでさえ、自然キーではありません。複合主キーは、起こるのを待っている災害です。そのデータを編集することはできません (これは、複合キーであるかどうかにかかわらず、自然キーの主な欠点です)。さらに悪いことに、複合キーでは、そのキー データを関連するすべてのテーブルに永続化する必要があります。なんて巨大な無駄。

現在、代理キーを選択するために、ID 列を使用しています (主に MS SQL Server で作業しています)。GUID は大きすぎるため、Microsoft は GUIDを PK として使用しないことを推奨しています。複数のサーバーがある場合は、同期/拡張する必要があるサーバーの最大数を 10 または 20 または任意の数だけ増分し、後続の各サーバーの各テーブルのシードを増分するだけです。 、データの衝突が発生することはありません。

もちろん、インクリメントのために、ID 列を BigInt (別名 long [64 ビット]) にします。

少し計算すると、インクリメントを 100 にしたとしても、テーブルには 92,233,720,368,547,758 (> 92 千兆) 行を含めることができます。

于 2008-12-31T22:15:52.677 に答える
9

「プライマリ」キーというフレーズでの「プライマリ」という言葉の使用は、本当の意味で誤解を招くと思います。

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

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

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

  4. 同じ論理エンティティを表す重複する行がテーブルに挿入されるのを防ぎ、データの一貫性を確保する。(これはしばしば「自然」キーと呼ばれ、比較的不変なテーブル (エンティティ) 属性で構成される必要があります。)

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

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

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

GUID に関しては、インデックスで GUID を使用するとインデックスの断片化が発生する可能性があるため、慎重に使用してください。それらを作成するために使用される最も一般的なアルゴリズムは、guid の「ランダム」部分を最も重要なビット位置に配置します...これにより、新しい行が追加されると、定期的なインデックスの最適化/再インデックス化の要件が増加します。

于 2008-12-31T22:02:17.493 に答える
8

絶対にやってはいけないことの 1 つは、スマート キーを使用することです。それはレコードに関する情報がキー自体にコード化されているキーであり、最終的には噛み付きます。

私が働いていた場所では、主キーは文字と数字の組み合わせであるアカウント ID でした。詳細は覚えていませんが、たとえば、特定のタイプのアカウントは 600 の範囲にあり、別のタイプのアカウントは 400 から始まりました。顧客が両方を要求するまで、それは素晴らしかったです。仕事の種類。または、彼らが行った仕事の種類を変更しました。

別の場所では、ツリー内の場所をレコードの主キーとして使用していました。したがって、次のようなレコードがあります。

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

もちろん、顧客が最初に望んだのは、ツリー内のアイテムを移動する方法でした。それが起こる前に、ソフトウェアのセット全体が死亡しました。

お願い、お願い、お願い、私が管理しなければならないコードを書いているのなら、スマートキーを使わないで!

于 2008-12-31T22:25:09.600 に答える
4

私は主キーとしての自動インクリメントのファンです。私はこれが警官であることを心の奥底で知っていますが、追加されたときにデータを並べ替えるのが非常に簡単になります(ID DESCで並べ替え、f'rインスタンス)。

3 列は、人間が解析するには非常に厳しいように聞こえます。

そして、それはトレードオフです-必要なリレーショナル機能の量と、 THIS TABLE RIGHT HERE を人間が質問する人間が理解できるようにすること(ストアドプロシージャまたはプログラムインターフェイスと比較して)。

自動インクリメントは私たち人間のためのものです。:-(

于 2008-12-31T21:20:13.130 に答える
4

一般的に、それは依存します。

個人的には、自動インクリメント int が好きです。

ただし、1 つ言えることは、他のソースからのデータをキーとして決して信頼しないことです。私がそれをするたびに、それは私を噛むために戻ってくることを誓います。まあ、二度と!

于 2008-12-31T21:21:01.397 に答える
3

主キーを構成する列は少なくとも 3 つ必要です。

私はこれを理解していません。

「名前と生年月日」などの「自然キー」について話しているのですか?自然キーが存在する場合は理想的ですが、自然キーのほとんどの候補は一意ではない (同じ名前を持つ複数の人) か、一定ではありません (誰かが名前を変更できる)。

自動インクリメントが十分な主キーである Int/ BigInt 。

私はギドの方が好きです。自動インクリメントの潜在的な問題は、値 (例: "order id") がデータベース インスタンス (例: "sales database") によって割り当てられることです...これは完全には機能しません (代わりに複合キーが必要になります)。複数のデータベース インスタンス (それぞれ独自のデータベースを持つ複数の営業所など) によって作成されたデータをマージする必要がある場合があります。

于 2008-12-31T21:25:07.270 に答える
3

RE GUID

これが本当に本当に本当に本当に大きなデータベースになり、多くの負荷がかかり、アクセスが高速になるかどうかに注意してください。

私の最後の仕事では、1 億から 5 億のレコードのデータベースがありましたが、データベース担当者は GUID に反対し、適切なサイズの 10 進数を求めて強く主張しました。彼らは、(Oracle の下で) 文字列 Guid の内部ストレージのサイズの違いと 10 進数の値の違いが、ルックアップで非常に顕著な違いを生むと感じました。(キーが大きい = トラバースするツリーが深くなる)

GUID のランダムな性質により、インデックス ページのフィル ファクターも大幅に減少します。これにより、ティアリングとディスク I/O が劇的に増加します。

于 2009-01-01T01:03:38.063 に答える
2

私は常に代理キー(「id」と呼ばれる自動インクリメント整数)を使用してきました。別のオプションが明らかな場合でも、これを行う理由はたくさんあります。

  • 一貫性
  • データに依存しない(一意、フォーマットの変更によって破壊されない)
  • 人間が読める形式

...そして次のことをしない賢明な理由はありません:

  • 結合のあいまいさ?-テーブルのエイリアシングはより良い方法です、IMHO
  • 最適なテーブル?-エントリごとに1バイトを削除するのは時期尚早の最適化です、IMHO
  • テーブルごとの決定?-一貫性がなくなった
  • スケーリングの問題?-え?なんで?
  • 階層的なデータ構造?-それは非正規化であり、他のすべての宗教の主題です。理論的にはいくつかの状況で私はファンだと言えば十分ですが、実際には決してありません:)

私がまだ考えていない、または出くわしていないという賢明な理由はいつでも歓迎されます...

于 2009-01-01T21:18:26.363 に答える
2

これは古典的な「場合による」です。すべてのプロジェクトに唯一の正解はありません。私はさまざまな状況でさまざまなものが好きです。ORM を使用しているかどうかと、それが何をサポートしているかによって異なります。全体的なアーキテクチャ (分散型かどうかなど) に依存します。うまくいくと思うものを1つ選んで、タブとスペースをめぐる議論に移ってください.

于 2008-12-31T21:16:34.777 に答える
2

私は、サイズ、接続人数、および複数のデータベース サーバーの状況に応じて、オプション #1 または #3 を使用する傾向があります。

オプション#2は私にはあまり意味がありません。3 つのうちの 1 つでも一意のレコードを識別するのに十分でない場合、2 つのレコードが 3 つの列すべてに同じ値で表示される可能性があります (余分な操作を行う必要はありません)。3 つの任意の組み合わせに一意性を適用する場合は、それらのインデックスを追加するだけです。

于 2008-12-31T21:22:22.253 に答える
2

列を自動インクリメントします。私は自分のコードを SQL Server または Oracle とシームレスに連携させることができ、一方は ID を使用し、もう一方は DAL を介したシーケンスを使用しており、これ以上ないほど幸せです。同意します。レプリケーションを行っている場合や、データを後で処理して受け取るためにデータを送信している場合は、GUID が必要になることがあります。

于 2008-12-31T22:29:17.390 に答える
1

自然キーは、信頼できるときはいつでも好きです。対象分野の専門家にとって意味のあるキーを使用するために、少額のパフォーマンス価格を支払うつもりです。

エンティティを説明するテーブルの場合、主題の人々が行うのと同じ方法で個々のインスタンスを識別する単純な自然キーが必要です。主題にエンティティの1つに対する信頼できる識別子がない場合は、代理キーを使用します。

関係を説明するテーブルには、複合キーを使用します。各コンポーネントは、関係に参加するエンティティを参照するため、エンティティテーブルの行を参照します。繰り返しますが、複合キーを使用した場合のパフォーマンスへの影響は一般に最小限です。

他の人が指摘しているように、「主キー」という用語は少し誤解を招く恐れがあります。リレーショナルデータモデルでは、使用される用語は「候補キー」です。1つのテーブルに複数の候補キーが存在する可能性があります。論理的には、それぞれが他と同じように優れています。それらの1つを「プライマリ」として選択し、そのキーを介してすべての参照を作成することは、設計者が行うことができる選択にすぎません。

于 2009-01-06T12:03:03.240 に答える
1

基本的な定義上の答えを過ぎた後、優れた主キーを構成するものは、主に宗教と休憩室の議論に委ねられます。個々の行に一意にマップされ、常にマップされるものがある場合、それは主キーとして正常に機能します。その時点を過ぎると、他の考慮事項があります。

  • 主キーの定義が複雑すぎませんか? 「ベストプラクティス」に従うために不必要な複雑さを導入することを避けていますか?
  • データベースの処理に必要なオーバーヘッドが少なくて済む、より優れた主キーはありますか (つまり、INTEGER と VARCHAR など)?
  • 主キーの一意性と定義された不変条件が変わらないことを絶対に確信していますか?

この最後のものは、ほとんどの人が GUID や自己インクリメント整数列などを使用するように惹きつけるものです。住所、電話番号、名字/姓などに依存するのはうまくいかないからです。私が考えることができる人々についての唯一の不変性はSSNですが、それらが永遠にユニークであり続けるかどうかは100%確実ではありません.

うまくいけば、これがいくつかの明確さを追加するのに役立ちます...

于 2008-12-31T21:45:01.787 に答える
1

私が主キーにアプローチする方法 (そして私はそれが最善だと感じています) は、「デフォルト」のアプローチを避けることです。これは、自動インクリメント整数を平手打ちしてそれを 1 日と呼ぶのではなく、問題を見て、「常に変化せず、常に変化しない列または列のグループがあるか?」ということを意味します。答えが「はい」の場合、私はそのアプローチを取ります。

于 2008-12-31T21:49:33.570 に答える
1

ほとんど常に整数。

処理が小さい/高速である以外にも、他の正当な理由があります。「404040」と「3463b5a2-a02b-4fd4-aa0f-1d3c0450026c」のどちらを書き留めますか?

于 2008-12-31T21:57:10.640 に答える
1

Guids.期間。

スケールアウトする必要がある場合、または別の方法で主キーを割り当てる必要がある場合、それらはあなたの友達になります。他のすべてのインデックスを追加できます。


私の声明を明確にするために更新してください。

さまざまな種類のサイトで多くの作業を行ってきました。小規模な単一サーバーの取引から、複数の DB および Web サーバーに支えられた大規模な取引まで。主キーとして自動インクリメント int を使用しても問題ないアプリが確かにありました。しかし、それらは私のやり方のモデルには適合しません。

GUID を使用すると、どこでも ID を生成できます。これは、リモート サーバー、Web アプリ、データベース自体、またはマルチマスター環境の複数のデータベース内で生成される可能性があります。

一方、自動インクリメントされた INT は、プライマリ データベース内でのみ安全に生成できます。繰り返しになりますが、アプリケーションがその 1 つのバッキング DB サーバーに密接に結び付けられており、スケールアウトを気にする必要がない場合は 、これで問題ないかもしれません。

確かに、GUID を使用するということは、毎晩の再インデックス処理が必要になることを意味します。ただし、自動インクリメントされた INT 以外のものを使用している場合は、とにかくそれを行う必要があります。一体、プライマリとして INT を使用しても、断片化に対処するために再生成する必要がある他のインデックスがある可能性があります。したがって、GUID を使用しても別の問題が発生するわけではありません。これらのタスクは関係なく実行する必要があるためです。

大規模なアプリを見てみると、重要なことに気付くでしょう。それらはすべて Base64 でエンコードされた GUID をキーとして使用しています。この理由は単純です。GUID を使用すると簡単にスケールアウトできますが、INT をスケールアウトしようとすると、多くの困難を乗り越えなければなりません。

私たちの最新のアプリは、約 1 か月続く重い挿入の期間を経ています。その後、クエリの 90% 以上がすべてレポート用に選択されます。容量を増やすために、この大規模な挿入期間中に追加の DB サーバーを立ち上げることができます。後でそれらをレポート用の単一の DB に簡単にマージします。INTでそれを行おうとすると、絶対に悪夢になります。

率直に言って、データベースをクラスター化するか、レプリケーションをセットアップするときはいつでも、DB サーバーはテーブルに GUID を持っていることを要求します。したがって、システムを拡張する必要があると思われる場合は、適切なものを選択してください。

于 2008-12-31T21:27:02.710 に答える
1

自動インクリメント int または GUID のみを使用しています。99% の時間で自動インクリメント int を使用しています。これは、データベースについて初めて学んだときに使用するように教えられたものであり、データベースを使用しない理由に遭遇したことはありません (ただし、GUID の方が優れている理由は知っています)。

読みやすさに役立つため、自動インクリメントintが好きです。たとえば、「レコード 129383 を見てください」と言うと、誰かが入ってそれを見つけるのは非常に簡単です。ほとんど不可能な GUID を使用します。

于 2008-12-31T21:32:28.457 に答える
1

少しだけ関連がありますが、小さな分類テーブル (本質的にコードで ENUM を表すもの) があるときに最近やり始めたことの 1 つは、主キーを char(3) または char(4) にすることです。次に、ルックアップ値を表す主キーを作成します。

たとえば、社内の販売代理店向けの見積もりシステムがあります。すべての見積品目にいずれかが割り当てられる「コスト カテゴリ」があります。 「ODC」。ルックアップ テーブルの他の列には、コードの通常の英語の意味、「材料」、「サービス」、「旅行」、「税金」、「その他の直接費」などの詳細が格納されます。

int 以外のスペースを使用しないため、これは非常に便利です。また、ソース データを見ているときに、値が何であるかを知るためにルックアップ テーブルをリンクする必要はありません。たとえば、引用行は次のようになります。

1 部品番号 $40 MTL
2 その他の部品番号 $29.99 SVC
3 部品番号 2 $150 TRV

int を使用してカテゴリを表し、すべての行で 1、2、3 をリンクする方がはるかに簡単です。目の前にデータがあり、パフォーマンスはまったく影響を受けていないようです (私がそうではありません)。実際にテストしました。)

本当の質問に関する限り...私はRowGUIDのuniqueidentifiersが好きです。私はこれについて 100% ではありませんが、とにかくすべての行に内部 RowGuid があるわけではありませんか?? もしそうなら、RowGuid を使用すると、実際には int よりもスペースが少なくて済みます (または、それ以外のことはありません)。私が知っているのは、M$ が GreatPlains で使用するのに十分であれば、それで十分だということだけです。(私はアヒルするべきですか??)

于 2008-12-31T23:56:54.687 に答える
1

GUID を使用するもう 1 つの理由は、階層データ構造を使用することです。つまり、主キーが一致するテーブル「Company」とテーブル「Vendor」があります。しかし、会社からも「継承」する「製造元」テーブルもあります。Vendors と Manufacturers に共通のフィールドは、これらのテーブルには表示されません。Company に表示されます。このセットアップでは、int の使用は Guid よりもはるかに苦痛です。少なくとも、ID の主キーは使用できません。

于 2009-01-01T00:00:00.733 に答える
0

これは、気付いているかどうかにかかわらず、複雑な問題です。この StackOverflow FAQ のセクションに該当する可能性があります。

ここで聞いてはいけない質問とは?

主観的、論争的、または長時間の議論を必要とする質問をすることは避けてください。答えられる質問の場です!

これは何年も議論されており、今後も議論が続くでしょう。私が見たコンセンサスの唯一のヒントは、OO 担当者 (GUID が唯一の方法です!)、データ モデラー (自然キーが唯一の方法です!)、またはパフォーマンス指向の DBA (INT が唯一の方法です!)。

于 2008-12-31T21:27:06.317 に答える