1. ホーム
  2. mongodb

[解決済み] MongoDBでObjectIDの代わりにUUIDを使用する方法

2022-11-09 09:32:30

質問

パフォーマンス上の理由から MySQL から MongoDB にデータベースを移行しており、MongoDB ドキュメントの ID に何を使用するか検討しています。MongoDB のデフォルトである ObjectID を使用するか、代わりに UUID を使用するか (これは MySQL で今まで使用してきたものです) を議論しています。今のところ、これらのオプションのいずれかをサポートするために私たちが持っている議論は次のとおりです。

ObjectIDsです。 ObjectID は MongoDB のデフォルトで、これには理由があると思います (確信はありませんが)。つまり、MongoDB は UUID よりも効率的に処理できる、あるいは別の理由でこれを好んでいるのだろうと思います。また このstackoverflowの回答 には、ObjectIDを使うことでインデックス作成がより効率的になると書かれています。

UUID。 UUIDの使用を支持する私たちの基本的な議論 (そしてそれは非常に重要なものです) は、事実上すべてのデータベースで、何らかの形でサポートされていることです。つまり、将来的に何らかの理由でMongoDBから他のデータベースに切り替えることになったとき、すでにIDに基づいてDBからドキュメントを取得するAPIがあれば、このAPIのクライアントにとっては何も変わらないということです。もしObjectIDを使用するのであれば、他のDBにどのように移行すればいいのかよくわかりません。

これらのオプションのうちの 1 つが他よりも優れているかどうか、またその理由について、どなたか洞察をお持ちですか? ObjectID の代わりに MongoDB で UUID を使用したことがあり、その場合、どのような利点と問題がありましたか?

どのように解決しますか?

Mongo で UUID を使うことは確かに可能で、それなりにサポートされています。たとえば、Mongo のドキュメントでは UUID は の共通オプションとして UUID を挙げています。 _id フィールド .

考察

  • 性能 - 他の回答にもあるように ベンチマーク は、UUID が挿入のパフォーマンス低下を引き起こすことを示しています。測定された最悪のケース (コレクション内のドキュメントが 10M から 20M になる) では、約 ~2-3 倍遅くなりました。これは、1 秒あたり 2,000 (UUID) と 7,500 (ObjectID) のドキュメントを挿入する場合の差です。これは大きな違いですが、その重要性は使用するケースに完全に依存します。一度に何百万ものドキュメントを一括挿入するのでしょうか?私が作ったほとんどのアプリでは、個々の文書を挿入するのが一般的なケースです。同じベンチマークによると、その使用パターンでは、この差は はるかに より小さくなりました (6,250 対 7,500、~20%)。些細なことではありませんが、驚異的でもありません。

  • 携帯性 - 他の多くのDBプラットフォームは優れたUUIDサポートを持っているので、移植性は改善されるでしょう。あるいは、UUID はより大きい (ビット数が多い) ので、以下のようにすることも可能です。 ObjectID を UUID の形状に再パックすることができます。 . このアプローチは、直接的な移植性ほど良いものではありませんが、既存の ObjectID と UUID の間の "マップ" を行う方法を提供します。
  • 分散化 - UUID の大きなセールスポイントの 1 つは、普遍的にユニークであるということです。このため、どこでも分散的に生成することができます (たとえば自動インクリメントの値では、次の値を決定するために一元的な情報源が必要になるのと対照的です)。もちろん Mongo オブジェクト ID にもこの利点があります。違いは、UUID は 15 年以上前の標準に基づいており、 (ほぼ) すべてのプラットフォームや言語でサポートされていることです。そのため、エンティティ (具体的には、email のセット) を作る必要がある場合に非常に便利です。 関連する エンティティを作成する必要がある場合、非常に便利です。ID と外部キーでデータセットを作成し、将来のある時点でグラフ全体をデータベースに書き込めば、衝突することはありません。これは Mongo ObjectID でも可能ですが、ObjectID を生成したりこのフォーマットで動作させたりするコードを見つけるのは、しばしば困難でしょう。

修正

他のいくつかの回答とは異なります。

  • UUID は Mongo のネイティブサポートです。 - を使うことができます。 UUID() 機能 を使うのとまったく同じように Mongo Shell で ObjectID() を使うのと同じです。 UUID 文字列を同等の BSON オブジェクトに変換します。 .
  • UUIDは特に大きくはありません - バイナリサブタイプでエンコードした場合 0x04 でエンコードされた場合、ObjectID の 96 ビットに対して、128 ビットです。(文字列としてエンコードされた場合は となります。 は約 288 ビットとなり、かなり無駄が多くなります)。
  • UUIDはタイムスタンプを含むことができます。 - 具体的には、UUIDv1 はタイムスタンプを 60 ビットの精度でエンコードします。これは6桁以上高い精度であり、秒単位ではなくナノ秒単位です。 しかし、Mongo/JS の Date オブジェクトがサポートするよりも正確なタイムスタンプを保存する方法として、これは有効です。
    • でのビルドは UUID() 関数は v4 (ランダム) UUID しか生成しないので、これを利用するにはアプリか Mongo ドライバで ID を作成する必要があります。
    • ObjectID とは異なり を使うので、UUID がチャンクされる方法 のため、タイムスタンプは自然な順序を与えません。これは、ユースケースによって、良いことも悪いこともあります。(新しい標準はこれを変更する可能性があります。以下の 2021 年の更新を参照してください)。
    • ID にタイムスタンプを含めることは、時には悪い考えです。ID が公開されるあらゆる場所で、ドキュメントの作成時刻を漏えいすることになるからです。(もちろん、ObjectID もタイムスタンプをエンコードするので、これはそれらにも部分的に当てはまります)。
    • (仕様に準拠した) v1 UUID でこれを行う場合、サーバーの MAC アドレスの一部もエンコードすることになり、次のような可能性があります。 潜在的に マシンを識別するために使用される可能性があります。おそらくほとんどのシステムで問題にはなりませんが、理想的でもありません。(新しい標準はこれを変更する可能性があります。以下の 2021 年の更新を参照してください)。

結論

Mongo DB を単独で考えるなら、ObjectID は明らかな選択肢です。これはデフォルトでうまく動作し、完璧に機能します。代わりに UUID を使う を使用すると、値を扱うとき (バイナリ型に変換する必要があるなど) とパフォーマンスの両方の点で、多少の摩擦が発生します。このわずかな不便さが、標準化された ID フォーマットを持つ価値があるかどうかは、移植性とアーキテクチャーの選択に重点を置くかどうかに実際に依存します。

異なるデータベースプラットフォーム間でデータを同期させるのですか? 将来的にデータを別のプラットフォームに移行する予定ですか? ID を生成する必要がありますか? 外部に を生成する必要がありますか?今でなくとも、将来のある時点で?UUID は手間をかける価値があるかもしれません。

2021 年 8 月更新

IEFT は最近、UUID フォーマットのいくつかの新しいバージョンを導入する UUID 仕様の更新ドラフトを発表しました。

具体的には UUIDv6 UUIDv7 は UUIDv1 に基づいていますが、ビットが最上位から最下位に配置されるようにタイムスタンプチャンクを反転させています。これにより、結果として得られる値は、それらが作成された順序を (多かれ少なかれ) 反映する自然な順序となります。また、新しいバージョンでは、サーバーの MAC アドレスに由来するデータを除外し、v1 UUID に対する長年の批判に対処しています。

これらの変更が実装に反映されるには時間がかかりますが、(IMHO) フォーマットを大幅に近代化し、向上させるものです。