データベース行の主キーを作成するためのこれら 3 つの主な方法の長所と短所を検討しています。
では、これらの方法の 1 つ以上をサポートするデータベースを使用していると仮定すると、自分にとって最適なオプションを決定するための簡単なヒューリスティックはありますか?
分散/複数のマスター、パフォーマンス要件、ORM の使用、セキュリティ、テストなどの考慮事項は選択にどのように影響しますか?
予期せぬ欠点に遭遇する可能性はありますか?
ベストアンサー1
UUID
これらが「単調増加シーケンス」で生成されない限り、インデックスに重大な損傷/断片化が生じる可能性があります。UUID生成のサポートはシステムによって異なります。使用可能ではありますが、私はUUIDをプライマリクラスターほとんどの場合、インデックス/PK です。必要に応じて、セカンダリ列にします。インデックスが付けられる場合もあれば、付けられない場合もあります。
UUIDは任意の数のシステムからレコードを安全に生成/マージするために使用できると主張する人もいます。UUID(方法によって異なりますが)は一般的に衝突の可能性が非常に低いですが、少なくとも外部からの入力やとても運が悪いですね:) -- 衝突が発生します。真実PKはシステム間で伝送されるべきであるが、私はそれが(あるいはそうすべきではない)データベース生成ほとんどの場合、UUID です。
自動増分/シーケンスキーとシーケンステーブル
これは、データベースが適切にサポートしているものによって異なります。一部のデータベースは、単純な「自動増分」よりも柔軟なシーケンスをサポートしています。これは望ましい場合もあれば、そうでない場合もあります (または、単純にこの種のタスクを実行する唯一の方法である場合もあります)。シーケンス テーブルは一般にさらに柔軟ですが、この種の「柔軟性」が必要な場合は、特にトリガーの使用を伴う場合は、設計パターンに戻って検討したくなります。私は「制限のある ORM」を好みませんが、それが「より単純な」自動増分またはシーケンス タイプ/データベース サポートの選択に影響を与える可能性もあります。
どのような方法であっても、代理主キー、真の主キー依然として識別され、スキーマにエンコードされる必要があります。
さらに、私は「自動シーケンスPKの公開によるセキュリティ侵害」は、内部データベースプロパティ。CRUD操作を処理する非常に簡単な方法ですが、内部キーそしてその露出したキー(例: きれいな顧客番号)。
あくまでも私の意見です。
編集、ティムへの追加の返信:
生成された PK と実際の PK の質問は非常に良い質問であり、私も検討する必要があると思います。あなたが指摘した点については、UUID 全般について言及したいと思います。私が躊躇したのは、サイズと int/long のどちらにするかという点です。インデックスの最適化が失われる可能性については認識していませんでした。これは私にとってははるかに大きな懸念事項です。
サイズについてはあまり気にしないほうがいいでしょう。UUIDが最適であれば、それが最適です。そうでない場合は、そうではありません。全体的な計画int型に比べて12バイト多いことは、あまり意味がないと思われます。SQL Server 2005以降では、ニュースシーケンシャルID通常の UUID 生成に伴う断片化を回避するための UUID 生成関数。このページではこれについて少し説明しています。他のデータベースにも同様のソリューションがあるはずです。
「スキーマにエンコードする」とは、一意性制約を追加する以上のことを意味しますか?
はい。主キーが唯一の [一意の] 制約である必要はありません。代理 PK を使用するだけでは、データベース モデルが危険にさらされるわけではありません :-) 追加のインデックスを使用してカバーすることもできます。
また、「区別」とは、代理主キーが漏洩することはないということを言っているのでしょうか?
私の最初の投稿の文言は少し厳しかった。「決して」ではなく「もし彼らがそしてそれは重要なことだそれは別の問題です」。推測可能な数字によるセキュリティの弱さについて不満を言う人はよくいます。たとえば、あなたの順序が 23 なら、順序 22 と 24 などがある可能性が高いです。これが「保護」であり、機密情報を漏らす可能性がある場合、システムはすでに欠陥があります。(内部 ID と外部 ID を分離しても、この問題は本質的に解決されず、認証/承認は依然として必要です。ただし、これは「連続 ID」の使用に対して提起される問題の 1 つです。分散 URL に nonce をエンコードすると、この問題に対処できると思います。私のユースケースとしては、かなり良いと思います。
私が本当に伝えたかった: 代理 PK ID がたまたま 8942 だからといって、それが順序 8942 であることを意味するわけではありません。つまり、「一部のフィールドは DB 内部のみ」という設計に従うと、順序「番号」は表面的にはまったく無関係である可能性があります (ただし、DB モデルでは完全にサポートされています)。たとえば、「#2010-42c」など、ビジネス要件に適したものになります。これは外部のほとんどの場合に公開される必要がある番号。
他のフィールドは変更可能であるため (例: ユーザーが電子メールやユーザー名を変更する場合)、生成されたキーが実際には真の主キーである場合があるように感じます。
そうかもしれない内でデータベースであり、私はこの主張に異論を唱えるつもりはない。しかし、再び代理PKは内部データベースにエクスポート/インポートする場合は、確実に識別できるタプルのみをエクスポート/インポートするようにしてください。ユーザー名/電子メールが変更される場合、これにはアカウント作成時に割り当てられた UUID が含まれる可能性があり、代理 PK 自体である可能性もあります。
もちろん、他のことと同様に、オープンな姿勢を保ち、モデルを問題に当てはめ、問題をモデルに当てはめないようにしてください :-) たとえば、Twitter のようなサービスでは、独自の番号生成スキーマを使用します。Twitter の新しい ID 生成. [一部の] UUID生成とは異なり、Twitterによるアプローチ(すべてのサーバーが正しく設定されていると仮定)保証分散マシン/プロセスはいずれも重複した ID を生成せず、64 ビットのみを必要とし、大まかな順序を維持します (最上位ビットはタイムスタンプです)。(Twitter によって生成されるレコードの数は、ローカル要件とはまったく関係がない可能性があります ;-)
楽しいコーディングを。