MongoDb in action-オンラインストア

MongoDbに出会ってから1年が経ちます。 私は彼女と一緒に仕事を始めたのは初めてではありませんでしたが、それでもなお、この技術は実験的なものとして認識されています。

一般的に、私はこう言います:MongoDBでの作業はMS SQLよりも便利です。 定期的にSQLよりも多くの労力を必要とするスクリプトがありますが、その結果、データベースの配置方法についてより多くの知識を持ち、スローダウンするものとしないものをより適切に制御できます。

habrにはHello Worldスタイルのアプリケーションがたくさんあるため、環境の初期化を省略して、より高度な問題に直接進みます。


テーブルに従ってではなく、オブジェクト全体を保存する方が便利なのはなぜですか?


多くのプログラマーにとって、主キーでもレコードを取得することは時間の大きな投資であることはまだ明らかではありません。 これを知っている必要はないようです。自分用にテーブルを用意し、検索用のストアドプロシージャを作成してください。他のことは心配できません。 ただし、実際には、オブジェクトが平らになることはめったになく、最愛の遅延読み込みメカニズムはシステムの動作時間を非常に急速に壊滅的に悪化させます。
過去1年半にわたる私の実際の経験からのオブジェクトの組み合わせの例を次に示します。
-製品には任意の数の写真とビデオがあります
-製品には任意の数の特性があります
-カテゴリには、それを表す製品があります
-新しいプロパティを追加する継承の場合、テーブル内のスペースを失うか、追加のサブクエリがあります
-オブジェクト名と説明は、任意の数の言語で提供されます。

そのようなスクリプトをC#で記述するのは簡単です。 しかし、数十万のレコードで機能する効果的なデータレイヤーを作成することは困難です。

同時に、MongoDBを使用すると、そのようなオブジェクトを1回の呼び出しで保存できます。
DocumentCollection.Save<T>(document); 

ネストされたすべてのクラスでダウンロードすることも基本です。
 DocumentCollection.FindOneById(id); 

たとえば、製品のプレゼンテーションを見てください。 データベースへの1回の呼び出しに対して-カテゴリIDおよびSeoFreindlyUrlで検索すると、0.0012秒かかります(!)
-適切な製品特性
-そのパラメーター(この場合は2つだけですが、一般にその数とタイプは任意です)
-画像(カテゴリで再利用、2個、それぞれURL +サイズあり)
-ビデオ(ある場合)
-関連製品(リンク)
-販売条件(このオブジェクトは、保証期間の継承された構成のカテゴリとシステム設定で再利用され、返品の可能性)
-メーカー
-Seo行(ブラウザータイトル、メタタグ、seoテキスト)

そして、すぐにレンダリングに進むことができます。

統計の場合:現在、製品テーブルには154千のエントリがあります。 平均して、1つのレコードには22KBが必要です。 テーブルサイズは4GBです。

SQL Serverを使用している場合、このような複雑なオブジェクトを読み取る最良の方法は、xmlのすべてのプロパティを手動でシリアル化することです。 MongoDBはこれをすべて手間をかけずに提供します。

システム全体は3つのクラスに基づいています。
-BaseMongoClass(ID、タイトル、LastChanged)
-EntityRef(リンク、IDとタイトルを含む、より洗練された相続人がいます)
-BaseRepository。作業に必要なすべてのメソッドを実装します。 GetById、Get(クエリ)、FirstOrDefault、GetAll、GetByIds(IDリストによる)、GetByEntityRefs(EntityRefリストによる)、Save、DeleteById、DeleteByQueryを選択しました。

特定のリポジトリはBaseRepositoryから単純に継承され、コレクションのタイプと名前(mongoの観点ではこれはテーブルの名前)を示し、「カテゴリごとに製品を見つける」など、ロジックレベルで既にいくつかの操作を実装します。

MongoDBは、階層情報を保存する必要がある場合に最も便利なベースです。 世界では、フラットデータは非常に小さくなっています。

PS: 基本的なクラスとリポジトリのリストはこちらからダウンロードできます

関係に対処するには?



もちろん、mongoには関係がありません。 abo.uaプロジェクトは、次のアプローチを使用します。

製品には1つのカテゴリを含めることができます(さらに多くのカテゴリがありますが、少し簡略化しています)。 製品自体のタイプには、次のように書かれています。
 public EntityRef Category { get; set; } [BsonIgnore] // ,      public Category CategoryValue { get { if (Category == null || Category .IsEmpty()) return null; return AppRequestContext.Factory.BuildCategoryRepository().GetById(Category.Id); } } 

カテゴリーを変更するとき、カテゴリーを設定します。 カテゴリについてより詳細な情報を学習する便利な方法が必要な場合は、CategoryValueを使用します。

カテゴリの校正とデシリアライズに時間を無駄にしないために、もちろんその数は比較的まれですが、CategoryRepositoryはすべてをRAMにキャッシュします。ObjectId-> Category辞書では、MongoDBの呼び出しを超える速度です。
少なくともいくつかのカテゴリが変更されると、辞書全体を再構築します。

もちろん、メモリデータベースを使用することもできますが、実験により、プロセスのメモリよりも基本的に遅いことが示されています。

別のリレーショナルの問題は、関連オブジェクトの情報を更新することです。 たとえば、カテゴリは変更/削除されましたが、製品に関連情報が必要です:
1.常に非総合的な情報に備えてください。 上記のコードから、そのようなカテゴリがない場合、CategoryValueはnullを返します。 Webサイトはコード404を返します。これは別の単純なシナリオです。 商品を差し引くとき、プロパティを商品のタイプの定義と比較します:いくつかのプロパティは削除されましたか? 許可されている値のリストを変更しましたか? 型に追加されたプロパティのデフォルト値は何ですか? 複雑に聞こえますが、実際には、すべてのデータが手元にある場合、0.1秒以内に1000個の製品を表示できます。これで十分です。
2.データの整合性を「修復」するコードを教えた後、データベース内のデータを修正するコードを簡単に書くことができます。 次のようになります。
 var products = prodRepo.GetAll().OrderBy(p => p.Id).Skip(start).Take(portionSize).ToArray(); prodRepo.JoinPropertyTypes(products); //       products.AsParallel().ForAll(p => prodRepo.Save(p)); 

残っているのは、影響を受けたすべてのオブジェクトに対してそのようなコードを(非同期で)呼び出すことだけです。

次の部分で


私が説明します:

Source: https://habr.com/ru/post/J149047/


All Articles