80

私はこの NOSQL 全体に不慣れで、最近 mongoDB に興味を持っています。私はゼロから新しい Web サイトを作成しており、MONGODB/NORM (C# 用) を唯一のデータベースとして使用することにしました。私はドキュメント モデル データベースを適切に設計する方法について多くのことを調べてきましたが、ほとんどの場合、設計はうまく機能していると思います。新しいサイトを始めて約 6 か月になりますが、何度も何度も対処しなければならないデータの複製/同期に関する問題が発生し始めています。私が読んだところによると、これはドキュメント モデルで想定されていることであり、パフォーマンスに関しては理にかなっています。IE 埋め込みオブジェクトをドキュメントに貼り付けて、読みやすくします - 結合はありません。もちろん、常に埋め込むことはできないため、mongodb には、基本的にリレーショナル DB の外部キーに類似した DbReference の概念があります。

ここに例を示します。ユーザーとイベントがあります。どちらも独自のドキュメントを取得し、ユーザーはイベントに参加し、イベントにはユーザーの出席者がいます。データが限られているイベントのリストを User オブジェクトに埋め込むことにしました。ユーザーのリストを「出席者」として Event オブジェクトにも埋め込みました。ここでの問題は、Event オブジェクトにも埋め込まれているユーザーのリストとユーザーを同期させておく必要があることです。私がそれを読んだとき、これは好ましいアプローチであり、物事を行うNOSQLの方法であるようです。取得は高速ですが、フォールバックはメインの User ドキュメントを更新するときです。Event オブジェクトにもアクセスする必要があり、おそらくそのユーザーへのすべての参照を見つけて更新する必要があります。

私が持っている質問は、これは人々が対処する必要がある非常に一般的な問題ですか? 「おそらく NOSQL 戦略は、私がここでやろうとしていることに適合しない」と言い始める前に、この問題がどのくらい発生する必要がありますか? 結合を行う必要がないというパフォーマンスの利点が、埋め込みオブジェクトでデータの同期を維持し、そのために DB に対して複数の読み取りを行うのに苦労しているために、いつ不利になるのでしょうか?

4

2 に答える 2

68

それはドキュメント ストアとのトレードオフです。標準の RDMS と同じように正規化された方法で保存できますが、できる限り正規化するように努力する必要があります。正規化を破ってデータ構造を平坦化する必要があるのは、パフォーマンスが低下する場合だけです。トレードオフは、読み取り効率と更新コストです。

Mongo には、従来の RDMS のように正規化を容易にする非常に効率的なインデックスがあります (ほとんどのドキュメント ストアはこれを無料で提供していません。そのため、Mongo は純粋なドキュメント ストアではなくハイブリッドに近いものになっています)。これを使用して、ユーザーとイベント間の関係コレクションを作成できます。これは、表形式データ ストアの代理テーブルに似ています。イベント フィールドとユーザー フィールドにインデックスを付けます。これは非常に高速で、データをより適切に正規化するのに役立ちます。

私は、レコード データの更新とクエリで必要なものの読み取りにかかる時間に関して、構造のフラット化と正規化の維持の効率をプロットするのが好きです。ビッグオー記法でそれを行うことができますが、それほど派手である必要はありません。データのさまざまなモデルを使用したいくつかのユースケースに基づいて、いくつかの数字を紙に書き留めて、どれだけの作業が必要かについて良い直感をつかんでください.

基本的に、私が最初に行うことは、レコードが更新される回数と読み取られる頻度の確率を予測することです。次に、更新と読み取りの両方のコストが正規化またはフラット化されている場合 (または、私が考えることができる 2 つの部分的な組み合わせ... 多くの最適化オプション) を予測しようとします。次に、データをフラットに保つことによる節約と、正規化されたソースからデータを構築することによるコストを判断できます。すべての変数をプロットしたら、それをフラットに保つことで節約できる場合は、フラットに保ちます。

いくつかのヒント:

  • 迅速でアトミックな (完全に最新の) 高速ルックアップが必要な場合は、正規化よりもフラット化を優先し、更新時にヒットするソリューションが必要になる場合があります。
  • 更新を迅速に行い、すぐにアクセスする必要がある場合は、正規化を優先します。
  • 高速なルックアップが必要だが、完全に最新のデータは必要ない場合は、正規化されたデータをバッチ ジョブで構築することを検討してください (可能であれば map/reduce を使用します)。
  • クエリが高速である必要があり、更新がまれであり、更新にすぐにアクセスできる必要がない場合や、(更新がディスクに書き込まれたことを保証するために) 100% の時間でトランザクション レベルのロックを実行する必要がない場合は、更新をバックグラウンドで処理するキューに書き込むことを検討できます。(このモデルでは、後で競合の解決と和解に対処する必要があります)。
  • さまざまなモデルをプロファイリングします。後でデータ ストア構造をリファクタリングできるように、コード内にデータ クエリ抽象化レイヤー (ある意味で ORM のようなもの) を構築します。

他にも活用できるアイデアはたくさんあります。highscalabilty.org のように、CAP 定理を理解するためのすばらしいブログがオンライン上にたくさんあります。

また、Redis や memcache などのキャッシュ レイヤーも検討してください。これらの製品の 1 つをデータ層の前に置きます。mongo (正規化されたものをすべて格納している) にクエリを実行すると、データを使用して平坦化された表現が構築され、キャッシュに格納されます。データを更新すると、更新対象を参照するキャッシュ内のすべてのデータが無効になります。(ただし、スケーリング係数を考慮して、更新されるキャッシュ内のデータと追跡データを無効にするのに時間がかかる必要があります)。「コンピューター サイエンスで最も難しい 2 つのことは、名前付けとキャッシュの無効化です」と誰かが言ったことがあります。

それが役立つことを願っています!

于 2010-10-24T20:09:02.727 に答える
0

タイプ UserEvent プロパティの IList を User オブジェクトに追加してみてください。ドメイン モデルの設計方法についてはあまり指定していません。例については、NoRM グループhttp://groups.google.com/group/norm-mongodb/topics を確認してください。

于 2010-10-24T23:18:24.347 に答える