web-dev-qa-db-ja.com

MongoDBに自動インクリメントを実装する必要がありますか?

MySQLからMongoDBに切り替えています。非常に基本的なusersテーブルでおなじみのアーキテクチャでは、uidが自動インクリメントされます。 この使用例については、Mongo独自のドキュメントを参照してください

これが最良のアーキテクチャ決定であるかどうか疑問に思っています。 UXの観点から、私はUIDを外部参照として、たとえばより短いURLで使用するのが好きです:http://example.com/users/12345

3番目の方法はありますか? IRC Freenodeの#mongodbの誰かが、IDの範囲を作成してそれらをキャッシュすることを提案しました。実際にそれを実装する方法や、他に行けるルートがあるかどうかわかりません。私はこのように_id自体をインクリメントする必要は必ずしもありません。usersがすべてドキュメント内で一意の数値uidを持っている限り、私は幸福です。

42
Josh Smith

Josh、MongoDBには自動インクリメントIDはなく、それには十分な理由があります。クラスタ内で一意のObjectIdsを使用します。

シーケンスコレクションによって自動インクリメントを追加し、findAndModifyを使用して、次に使用するIDを取得できます。これにより、アプリケーションが間違いなく複雑になり、データベースをシャーディングする機能にも影響する可能性があります。

生成されたIDが一意であることを保証できる限り、問題ありません。しかし、頭痛がするでしょう。

この質問の詳細については、MongoDB専用のGoogleグループでこの投稿をご覧ください。

http://groups.google.com/group/mongodb-user/browse_thread/thread/f57b712b2aae6f0b/b4315285e689b9a7?lnk=gst&q=projapati#b4315285e689b9a7

お役に立てれば。

ありがとう

18
kheya

MongoDBに自動インクリメントIDがないという選択された回答の作成者とは強く同意しません。十分な理由があります。 10genが自動インクリメントIDの使用を推奨しなかった理由はわかりません。それは推測です。クラスタ化された環境で12バイトIDの一意性を確保する方が簡単なため、10genがこの選択をしたと思います。これは、ほとんどの新規参入者に適合するデフォルトのソリューションであるため、10genのビジネスに適した製品の採用が増加します。

次に、商用環境でのObjectIdsの私の経験についてみんなに話させてください。

ソーシャルネットワークを構築しています。およそ600万人のユーザーがいて、各ユーザーにはおよそ20人の友達がいます。

次に、ユーザー間の関係(誰がフォローするか)を格納するコレクションがあるとします。こんな感じ

_id : ObjectId
user_id : ObjectId
followee_id : ObjectId

一意の複合インデックス{user_id, followee_id}。このインデックスのサイズは12 * 2 * 6M * 20 = 2GBと見積もることができます。これが、フォローしている人をすばやく検索するためのインデックスです。私をフォローしている人をすばやく検索するには、逆インデックスが必要です。それは別の2GBです。

そして、これはほんの始まりにすぎません。私はどこにでもこれらのIDを運ぶ必要があります。ニュースフィードを保存するアクティビティクラスターがあります。それはあなたやあなたの友達がするすべてのイベントです。どれだけのスペースが必要か想像してみてください。

そして最後に、私たちのエンジニアの1人が無意識のうちに決定し、サイズを2倍にするObjectIdを表す文字列として参照を保存することにしました。

インデックスがRAMに適合しない場合はどうなりますか?良いことは何もありません、10genは言います:

インデックスが大きすぎてRAMに収まらない場合、MongoDBはディスクからインデックスを読み取る必要があります。これは、RAMから読み取るよりもはるかに遅い操作です。インデックスはRAMサーバーにRAMインデックスが残りのワーキングセットと組み合わせて使用​​できる場合)に適合します。

つまり、読み取りが遅いということです。ロックの競合が発生します。書き込みも遅くなります。 80%ニッシュでロックの競合が発生しても、ショックはありません。

あなたがそれを知る前に、あなたはシャードに分割しなければならず、操作するのが非常に難しい460GBのクラスターになりました。

FacebookはユーザーIDとして64ビット長を使用します:)その理由はあります。連続したIDを生成できます

  • 10genのアドバイス を使用します。
  • mysqlをカウンターのストレージとして使用する(速度が気になる場合は handlersocket を見てください)
  • 作成したID生成サービスを使用するか、Twitterで Snowflake のようなものを使用します。

それで、ここに皆さんへの私の一般的なアドバイスがあります。データはできるだけ小さくしてください。成長すると、眠れない夜をたくさん節約できます。

84
expert

したがって、「自動インクリメント」IDには根本的な問題があります。 10の異なるサーバーがある場合(shards MongoDBの場合)、次のIDを選択するのは誰ですか?

自動インクリメントIDの単一のセットが必要な場合は、それらのIDを選択するための単一の権限が必要です。 MySQLでは、書き込みを受け入れるサーバーが1つしかないため、これは一般に非常に簡単です。しかし、MongoDBの大規模なデプロイメントは、この「中央権限」を持たないシャーディングを実行しています。

MongoDBは12バイトのObjectIdsを使用しているため、各サーバーは単一の権限に依存することなく新しいドキュメントを一意に作成できます。

だからここに大きな質問があります:"あなたは単一の権限を持つ余裕があります"

その場合は、findAndModifyを使用して「最後に最も高いID」を追跡し、それを挿入できます。

それはあなたのリンクで説明されているプロセスです。ここで明らかな弱点は、技術的には挿入ごとに2つの書き込みを行わなければならないことです。これは十分にスケーリングされない可能性があります。おそらく、挿入率が高いデータではそれを避けたいでしょう。これはユーザーにとっては機能するかもしれませんが、クリックの追跡には機能しないでしょう。

16
Gates VP

MongoDBには自動インクリメントのようなものはありませんが、独自のカウンターを専用のコレクションに格納し、必要に応じてカウンターの関連する値を$ incできます。 $ incはアトミック操作であるため、重複は表示されません。

10
Andreas Jung

デフォルトのMongo ObjectId(_idフィールドで使用されるもの)は増加しています。

Mongoは、タイムスタンプ(Unixエポックからの秒数)をその4-3-2-3構成の最初の4バイト部分として使用します。バージョン1 UUIDと同じ構成(正確ではないにしても)に非常に似ています。そして、そのObjectIdは挿入時に生成されます(他のタイプの_idがユーザー/クライアントによって提供されていない場合)

したがって、ObjectIdは本質的に序数です。さらに、デフォルトのソートは、この増分するタイムスタンプに基づいています。

多くのdbmsで使用されている自動インクリメント(index ++)IDの更新バージョンと考えるかもしれません。

3
Gabe Rainbow