GUIDを主キーとして使用する

私は通常、データベースの主キーとして自動インクリメントのIDを使用しています。 GUIDを使用することの利点を学びたいと考えています。 私はこの記事を読みました: https://betterexplained.com/articles/the-quick-guide-to-guids/

このGUIDは、アプリケーション・レベルでオブジェクトを識別するために使用されると理解しています。 また、データベースレベルでも主キーとして保存されるのでしょうか。 例えば、次のようなクラスがあったとします。

public class Person
{
public GUID ID;
public string Name;
..

//Person Methods follow
}

メモリ上に新しいPersonを作成し、そのPersonをデータベースに挿入したいとします。 こうすればいいのか。

Person p1 = new Person();
p1.ID=GUID.NewGUID();
PersonRepository.Insert(p1);

GUIDを主キーとする数百万行のデータベースがあるとします。 これは常に一意になるのでしょうか?私はGUIDを正しく理解しているのでしょうか?

以前、この記事(http://enterprisecraftsmanship.com/2014/11/15/cqs-with-database-generated-ids/)を読みました。 GUIDと整数の中間を主キーとして推奨しているように見え、少し混乱しています。

11/06/18を編集しました。

私の要件には、intsよりもGuidsの方が適していると思うようになりました。 最近はCQRSを使うことが多くなり、GUIDの方がしっくりくるようになりました。

開発者によっては、GUIDをドメインモデルで文字列としてモデル化していることに気づきました。例えば、https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs - この場合。この場合、IdentityGuidは文字列としてモデル化されたGUIDである。 この場合、IdentityGuidは文字列としてモデル化される。このようにする理由は、ここに記載されている以外にあるのだろうか: https://softwareengineering.stackexchange.com/questions/239220/use-a-custom-value-object-or-a-guid-as-an-entity-identifier-in-a-distributed-sys。 GUID を文字列としてモデル化するのは普通ですか。それとも、モデルおよびデータベースで GUID としてモデル化する必要がありますか。

GUIDは定義上、"Globally Unique IDentifiers"(世界的にユニークな識別子)です。 JavaにはUUID(Universally Unique IDentifiers)と呼ばれる、似ているが少し異なるコンセプトがあります。 この2つの名称は、実用上、互換性があります。

GUIDは、マイクロソフトが想定していたデータベースクラスタリングの仕組みの中心であり、時々つながっているソースからデータを取り込む必要がある場合、データの衝突を防ぐのに非常に役立ちます。

プロGUIDの事実もあります。

  • GUIDはキーの衝突を防ぐ
  • GUIDは、ネットワークやマシンなどの間でデータを統合する際に役立ちます。
  • SQL Serverはインデックスの断片化を最小限にするためにセミシーケンシャルGUIDをサポートしている(ref、いくつか注意点がある)

GUIDの不都合な点

  • 1つ16バイトと大きい
  • 自動インクリメントIDのように、IDでソートして挿入順序を決めることはできません。
  • 彼らは、特に小さなデータセット(ルックアップテーブルのような)で動作するように、より面倒です。
  • 新しい GUID の実装は、C# ライブラリよりも SQL Server 上でより堅牢です(SQL Server ではシーケンシャルな GUID を持つことができ、C# ではランダムなものとなります)。

GUIDを使用するとインデックスが大きくなるため、カラムのインデックス作成にかかるディスクスペースのコストが高くなります。 ランダムなGUIDはインデックスを断片化する。

異なるネットワークからデータを同期させるつもりがないことが分かっている場合、GUIDはその価値以上にオーバーヘッドをもたらす可能性があります。

時々接続しているクライアントからデータを取り込む必要がある場合、これらのクライアントのシーケンス範囲を設定することに頼るよりも、キーの衝突を防ぐためにはるかに堅牢になる可能性があります。

解説 (23)

これは常にユニークなものなのでしょうか?

それはビットの有限なシーケンスです。

GUIDを主キーとする数百万行のデータベースがあったとします。

何百万も何千万もあれば、おそらく安全でしょう。 何百万もあれば、衝突の可能性は大きくなります。 しかし、良い知らせがあります。そのような事態になる前に、あなたはすでにディスクスペースを使い果たしているのです。

こんなことしていいんですか?

しかし、それは完全に良いアイデアではありません。 ドメインモデルは通常、乱数を生成すべきではありません; これらはモデルへの入力であるべきです。

さらに、信頼性の低いネットワークを扱っていて、重複したメッセージを受け取る可能性がある場合、_決定論的に生成されたUUIDは重複した実体を持つことからあなたを守ることができます。 しかし、それぞれに新しい乱数を割り当てるのであれば、重複を特定するための作業が増えることになります。

RFC 4122]2の名前ベースのuuidの説明を参照してください。

GUIDを文字列でモデル化するのは"normal"なのか、モデルやデータベースでGUIDとしてモデル化すべきなのか?

あまり関係ないと思います。 ドメインモデルの大部分では、それは_identifier_です;あなたがそれに対して求める唯一のクエリは、それが他の識別子と同じであるかどうかです。 ドメインモデルは通常、識別子のインメモリ表現を見ることはありません。

もしGUIDがドメインにとらわれない設定で"プリミティブ型"として利用できるのであれば、私はそれを使用します。

しかし、識別子の表現は、メモリ上とストレージ上の両方で、実装の中で決定していることであり、したがって、その決定と結びついたコードのフットプリントが小さくなるように手段を講じるべきであることを認識する必要があります。

解説 (8)

GUIDやUUIDは、その生成方法からユニークである可能性が非常に高く、中央当局と通信しなくてもユニークさを保証できる安全な方法となります。

GUIDを主キーにするメリット。

  • クラスタの異なるシャード間でデータをコピーしても、PKの衝突を心配する必要がない。
  • レコードを挿入する前に主キーを知ることができる。
  • 子レコードを挿入する際のトランザクションロジックを簡素化できる。
  • 容易に推測することができない。

ご提示いただいた例では

Person p1 = new Person();
p1.ID = GUID.NewGUID();
PersonRepository.Insert(p1);

挿入時前にGUIDを指定することで、連続した子レコードを挿入する際にデータベースとの往復を省き、同一トランザクション内でコミットすることができます。

Person p2 = new Person();
p2.ParentID = p1.ID
PersonRepository.Insert(p2);

GUIDを主キーにすることの弊害

  • 16バイトと大きいので、インデックスや外部キーの追加に伴い、より多くのスペースを消費することになります。
  • 本質的に乱数であるため、うまくソートできない。
  • インデックスの使い方がとてもとてもとても悪い。
  • 多くの葉が移動する。
  • 覚えるのが大変
  • それらは言語化するのが難しいです。
  • それらはURL'sを読むのが難しくすることができます。

シャーディングやクラスタリングを必要としないアプリケーションでは、intやbigintのような小さくてシンプルなデータ型にこだわるのがベストでしょう。

多くのデータベースは、GUIDによって引き起こされるストレージの問題を軽減しようとする独自の内部実装を持っており、SQL ServerはUUIDの順序付けを支援する関数newsequentialidを持ち、インデックスをより良く使用できるようにしています。

さらに、アプリケーションに携わるテスター、ユーザー、開発者の立場からすると、GUIDよりもIDを使用する方が、コミュニケーションを大幅に改善することができます。GUIDを電話越しに読むことを想像してみてください。

結局のところ、大規模なクラスタリングやURLの難読化が要件でない限り、自動インクリメントのIDにこだわる方がより現実的です。

解説 (11)