ネストされたエンティティとリーフエンティティプロパティの計算-SQLまたはNoSQLアプローチ


10

メニュー/レシピ管理という趣味のプロジェクトに取り組んでいます。

これは私の実体とそれらの関係がどのように見えるかです。

AにNutrientはプロパティがCodeあり、Value

Ingredientコレクションを持っていますNutrients

A RecipeにはコレクションがIngredientsあり、時々他のコレクションを持つことができますrecipes

Aは、Mealのコレクションを持っているRecipesし、Ingredients

A MenuのコレクションがありますMeals

関係は次のように表すことができます

メニューエンティティと関係

いずれかのページで、選択したメニューについて、その構成要素(食事、レシピ、成分、および対応する栄養素)に基づいて計算された有効栄養素情報を表示する必要があります。

現在、SQL Serverを使用してデータを格納しています。メニューの各食事から始めて栄養素の値を集計して、C#コードからチェーンを移動しています。

この計算はページがリクエストされ、構成要素が時々変更されるたびに行われるため、これは効率的な方法ではないと思います。

MenuNutrients({MenuId, NutrientId, Value})と呼ばれるテーブルを維持し、コンポーネント(食事、レシピ、成分)のいずれかが変更されたときに、このテーブルに有効な栄養素を追加/更新するバックグラウンドサービスがあることを考えていました。

GraphDBはこの要件に適していると思いますが、NoSQLへの私の露出は限られています。

特定のメニューの栄養素を表示するというこの要件に対する代替の解決策/アプローチは何ですか?

シナリオの説明が明確であることを願っています。


話しているオブジェクトはいくつですか?パフォーマンスは本当に問題になるのでしょうか?
2013年

@flup平均して、メニューには8つの食事を含めることができ、各食事には2つのレシピと2つの材料を含めることができます。各レシピには6〜8個の材料を含めることができます。
Chandu 2013年

あなたの矢は間違った方向にありませんか?
Branko Dimitrijevic 2013年

Nerd Dinner Entity Frameworkサンプルを見たことがありますか?
Akash Kava 2013年

回答:


8

要件とアーキテクチャに基づいて、パフォーマンス改善オプションがある場合があります。

NOSQL:
そこのようなNoSQLの対SQLの良い記事がたくさん、ありこれは、この

:私は部品の利益

のNoSQLを使用するには:

DBが3NFで あり、結合を行わない場合一連のテーブルを選択してすべてのオブジェクトをまとめるだけで、ほとんどの人がWebアプリで行うことです)。

使用すると、次の準備ができます。

  • 結局、RDBMSが自動的に行うような、さまざまなテーブル/コレクションからのデータの結合などを行うジョブを作成することになります。
  • NoSQLのクエリ機能は大幅に機能しなくなります。MongoDbはSQLに最も近いものかもしれませんが、それでも非常にはるかに遅れています。私を信じて。SQLクエリは非常に直感的で、柔軟で強力です。NoSqlクエリはそうではありません。
  • MongoDbクエリは、1つのコレクションからのみデータを取得し、1つのインデックスのみを利用できます。そして、MongoDbはおそらく最も柔軟なNoSQLデータベースの1つです。多くのシナリオでは、これは関連するレコードを見つけるためにサーバーへのラウンドトリップが増えることを意味します。次に、データの非正規化を開始します。これは、バックグラウンドジョブを意味します。
  • リレーショナルデータベースではないという事実は、データの整合性を確保するための外部キー制約がないことを意味します(パフォーマンスが悪いと考えられています)。これにより、最終的にデータベースにデータの不整合が生じることを保証します。準備して。ほとんどの場合、データベースの整合性を維持するためにプロセスまたはチェックの作成を開始します。これは、RDBMSに任せるよりもパフォーマンスが低下する可能性があります。
  • hibernateのような成熟したフレームワークは忘れてください。

、NOSQLを使用する上で役立つ記事を使用するかしないかを決めるの横NOSQL DBMSの比較をし、それらの意図はここで見つけることができ、低書き込みを読み取り、それらのいくつかは高に焦点を当てているように、マップ-削減、HA ...
外観を持ちますでランク付けし、それらの人気カテゴリ別に、役に立つかもしれません。


詳細をありがとう。リンクを確認してご連絡いたします。
チャンドゥ2013年

3

実際、グラフデータベースを使用する必要はなく、必要な値を1つ上のレベルに格納するだけです。とを格納するのOrderと同じOrderItemsです。注文が表示されるたびに合計を計算する必要はありません。代わりに、合計、バット、およびその他のものを計算し、それらをに格納しますOrder

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

3

Command Query Responsibility Segregationパターンを確認することをお勧めします。

基本的に、読み書きする単一のモデルを作成する代わりに、2つの異なるモデルを作成できます。1つは更新用に最適化され、もう1つはクエリ(読み取り、レポートなど)用に最適化されています。2つのモデルは、ドメインイベント(DDDを参照)を使用して(通常は結果整合性で)同期されます。

私は数か月前にこのパターンを研究し始め、それが私のソフトウェアのモデリング方法を本当に変えました。特にDDDやイベントソーシングなどの他の手法と併用すると、大きな変化になるため、簡単ではありません。しかし、それだけの価値があります。

ネット上には多くのリソースがあります。CQRSとDDD(および最終的にはイベントソーシング)を検索してください。

このパターンは、SQLとnoSqlの両方で使用できます。

あなたの場合、栄養素が変更されるたびにイベントを発生させて、読み取りに最適化された読み取りモデルを更新できます。読み取りモデルは、たとえばメニューの栄養素の非正規化されたビューにすることができます(効率的な読み取りのためにnosql dbを使用しないのはなぜですか)。実行する必要があるクエリに基づいて、複数の読み取りモデルを持つことができます。

このアプローチを使用するといくつかの影響がありますが、非常にスケーラブルで拡張可能です。


これは私が考えていたアプローチでしたが、読み取りモデルのデータを取得する方法がわかりませんでした(基本的に、いくつかのプロセスで読み取りモデルのデータを取得する必要があります)。
チャンドゥ2013年

通常、読み取りモデルは変更のたびに更新されます。クラッド操作を使用する代わりに、コマンドを使用してUI(タスクベース)を実装する必要があります。このようにして、すべてのコマンドが読み取りモデルに反映されます。他のクエリを実行する必要はありません。コマンドを設計することで、システムはユーザーの本当の意図を捉えることができます。

2

それは、メニューと栄養素を最初に取得する方法に大きく依存します。なぜそれは効率的ではないと思いますか?

私が理解していることから、あなたはDBに行って、メニューを取得し、次にもう一度、各レシピを取得し、それからもう一度、各成分を取得します。遅延の主な原因であるサーバーへのクエリとラウンドトリップが多いため、これは本当に非効率的です。これはSELECT N + 1問題として知られています。

JOINメニューから栄養素までのすべてのテーブルにsを使用して、単一のクエリですべてのデータをフェッチすることで、DBサーバーはすべての関係とインデックスを使用してデータを一度に取得できます。クライアントC#アプリは、最終結果のみを処理して表示します。そうすることは一つずつ行くよりもはるかに効率的です。

一般的に、リレーショナルデータベースは、適切なクエリ技術と重要なクエリに適切なインデックスを使用して、負荷のかかった大きなテーブルで非常に適切に実行できます。


ありがとうございます、それは結合に依存することを理解しています。メニューの構成要素が時々変わるため、誰かがページにアクセスするたびに計算を実行したくありません。代わりに、バックグラウンドサービスで計算を行い、必要に応じてテーブルから読み取るだけで済みます。計算の問題は、構成要素の1つが変更されたときにチェーン全体を識別することです。
チャンドゥ

JOIN適切なインデックス付けが行われている場合、サーバーに負担をかけない5または6 秒であっても(数百または数千の行のフェッチについて話している場合を除いて)、数個のリレーションシップを検索するだけでは、計算はまったく発生しません。設置されています。ビッグデータセットを使用する場合でも、常に結果全体に基づいてビューを構築し、パフォーマンスに問題が発生した場合は、ビューにインデックスを付けて結果を事前計算することもできます。

2

簡単に更新してクエリできるように、データをモデル化する最善の方法を考えるのに少し時間を費やしたようです。ただし、ここでデータへのアクセスを提供する必要があります。これら2つは別の問題です。

あなたは、ページのリロードがデータベースへの新しいクエリを引き起こしていると述べました。また、データベースは時々更新されること、また、更新が必要な場合はページにタイムリーに表示することも述べています。クエリのオーバーヘッドを減らす最善の方法は、クエリを実行しないことです。同じクエリを何度も実行して同じ結果が得られる場合は、しばらくの間それらをキャッシュしてみませんか?プロジェクトの残りの部分を変更せずに、上流にキャッシュを実装できるはずです。残りについて読むことをお勧めします。プロジェクトをrdbmsに実装するかnosqlに実装するかに関係なく、このタイプのパフォーマンスに関する問題は、データベースにアクセスする必要がある回数を減らすことで最もよく処理されます。同じレシピに対して60秒で100のリクエストがあるとします。60秒間キャッシュすると、データベースに1回しかヒットしないため、パフォーマンスが100倍向上します。nosqlに切り替えることで同じレベルの改善を確認するには、さらに多くの作業が必要になります。

Nosqlタイプのシステムは、大量のデータがある場合や、極端な読み取りまたは書き込み速度の要件がある場合に最適なソリューションになります。ただし、その余分なパフォーマンスは、参照整合性などを破棄することを犠牲にして得られます。


1

実験または知識目的でGraph-DBを試してみたいと思われますが、この例は明らかに、ノードをドリルダウン/アップできる階層データの例です。私はGraph / Neo DBの専門家ではありませんが、ユーザー/ユーザーがこのスキーマからデータを要求する方法はそれほど複雑ではないことがわかります。データベース/スキーマ設計の選択は、どのように、そしてどのタイプのデータがそれに対して照会されるかに非常に依存していると思います。SQLSERVER "HierarchyI" Dを使用しているので、このノードをツリーの一部として配置するには、私の観点からの最良のオプションです。


1

私の提案は、人間ではなく機械のように考えることです。繰り返しのように見えるかもしれませんが、それはどのマシンが得意かということです。自分に尋ねなければならないことの1つは、「ページに表示するために、とにかくすべてのオブジェクトを取得する必要がありますか?」ということです。はいの場合、データの取得と比較して、実行中の処理を続行します。単純な計算を行う場合、CPUサイクルは無視できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.