メニュー/レシピ管理という趣味のプロジェクトに取り組んでいます。
これは私の実体とそれらの関係がどのように見えるかです。
Nutrient
にはCode
およびValue
のプロパティがあります
Ingredient
にはNutrients
のコレクションがあります
Recipe
にはIngredients
のコレクションがあり、時々他のrecipes
のコレクションを持つことができます
Meal
にはRecipes
とIngredients
のコレクションがあります
Menu
にはMeals
のコレクションがあります
関係は次のように表すことができます
いずれかのページで、選択したメニューについて、その構成要素(食事、レシピ、成分、および対応する栄養素)に基づいて計算された有効栄養素情報を表示する必要があります。
現在のところ、SQL Serverを使用してデータを格納しています。メニューの各食事から始めて栄養素の値を集計して、C#コードからチェーンを移動しています。
このリクエストはページがリクエストされ、構成要素が時々変更されるたびに計算されるため、これは効率的な方法ではないと思います。
MenuNutrients({MenuId, NutrientId, Value}
)と呼ばれるテーブルを維持し、コンポーネント(食事、レシピ、成分)のいずれかが変更されたときに、このテーブルに有効な栄養素を追加/更新するバックグラウンドサービスがあることを考えていました。
GraphDBはこの要件に適していると思いますが、私のNoSQLへの露出は限られています。
特定のメニューの栄養素を表示するというこの要件に対する代替の解決策/アプローチは何ですか?.
シナリオの説明が明確であることを願っています。
要件とアーキテクチャに基づいて、パフォーマンス改善オプションがある場合があります。
RDBMS(Sql server)レベルで indexed views (matrialized)To improve read performance を使用できます。
基本的に、あなたがする必要があるのは:
通常のビューを作成します。
そのビューにクラスター化インデックスを作成します。
アプリケーションレベルでキャッシュメカニズムを使用すると、パフォーマンスが向上します。
キャッシングを使用することが可能で実現可能な場合、 singleton lazy cashing のようなキャッシュ戦略を用意すると役立ちます。
NoSql:
this や this のように、SqlとNoSqlに関する良い記事がたくさんあります。
パーツは私に興味があります:
NoSqlの使用場所:
DBが NFであり、結合を行わない場合(多数のテーブルを選択し、すべてのオブジェクトをまとめて、つまり、ほとんどの人がWebアプリで行うこと。
使用すると、次の準備ができます:
- 結局、RDBMSが自動的に行うような、さまざまなテーブルやコレクションからのデータの結合などを行うジョブを作成することになります。
- NoSQLのクエリ機能は大幅に機能しなくなります。 MongoDbはSQLに最も近いものかもしれませんが、それでも非常にはるかに遅れています。私を信じて。 SQLクエリは非常に直感的で、柔軟で強力です。 NoSqlクエリはそうではありません。
- MongoDbクエリは、1つのコレクションからのみデータを取得し、1つのインデックスのみを利用できます。そして、MongoDbはおそらく最も柔軟なNoSQLデータベースの1つです。多くのシナリオでは、これは関連するレコードを見つけるためにサーバーへのラウンドトリップが増えることを意味します。次に、データの非正規化を開始します。これは、バックグラウンドジョブを意味します。
- リレーショナルデータベースではないという事実は、データの整合性を確保するための外部キー制約がないことを意味します(一部の人はパフォーマンスが悪いと考えています)。これにより、最終的にデータベースにデータの不整合が生じることを保証します。準備して。ほとんどの場合、データベースの整合性を維持するためにプロセスまたはチェックの作成を開始します。これは、RDBMSに任せるよりもパフォーマンスが良くない可能性があります。
- Hibernateのような成熟したフレームワークは忘れてください。
NoSqlを使用するか使用しないかを決定する以外に、 NOSQL DBMSの比較とそれらの意図はここにあります それらのいくつかは高読み取り、低書き込み、マップ削減、 HA ...
カテゴリ別に それらのランキングと人気 を確認すると便利です。
実際、グラフデータベースを使用する必要はなく、必要な値を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?");
}
コマンドクエリの責任分離パターン を確認することをお勧めします。
基本的に、読み書きする単一のモデルを作成する代わりに、2つの異なるモデルを作成できます。 1つは更新用に最適化され、もう1つはクエリ(読み取り、レポートなど)用に最適化されています。 2つのモデルは、ドメインイベント(DDDを参照)を使用して(通常は結果整合性で)同期されます。
私は数か月前にこのパターンを研究し始め、それが私のソフトウェアのモデリング方法を本当に変えました。特にDDDやイベントソーシングなどの他の手法と併用すると、大きな変化になるため、簡単ではありません。しかし、それだけの価値があります。
ネット上には多くのリソースがあります。CQRSとDDD(および最終的にはイベントソーシング)を検索してください。
このパターンは、SQLとnoSqlの両方で使用できます。
あなたの場合、栄養素が変更されるたびにイベントを発生させて、読み取り用に最適化された読み取りモデルを更新できます。読み取りモデルは、たとえば、メニューの栄養素の非正規化ビューにすることができます(効率的な読み取りのためにnosql dbを使用しないのはなぜですか)。実行する必要があるクエリに基づいて、複数の読み取りモデルを持つことができます。
このアプローチを使用するといくつかの影響がありますが、非常にスケーラブルで拡張可能です。
それは、メニューと栄養素を最初に取得する方法に大きく依存します。なぜそれは効率的ではないと思いますか?
私が理解していることから、あなたはDBに行って、メニューを取得し、次に再び行き、各レシピを取得し、次に再び行き、各成分を取得します。遅延の主な原因であるサーバーへのクエリとラウンドトリップが多いため、これは本当に非効率的です。これはSELECT N + 1問題として知られています。
メニューから栄養素までのすべてのテーブルにJOIN
sを使用して、単一のクエリですべてのデータをフェッチすることにより、DBサーバーはすべての関係とインデックスを使用してデータをすべて取得できます。すぐに。クライアントC#アプリは、最終結果のみを処理して表示します。そうすることは、一つずつ行くよりもはるかに効率的です。
一般に、リレーショナルデータベースは、適切なクエリ技術と重要なクエリに適したインデックスを使用して、負荷のかかった大きなテーブルで非常に適切に実行できます。
データを簡単に更新してクエリできるようにデータをモデル化する最善の方法について、少し時間を費やしてきたようです。ただし、ここでデータへのアクセスを提供する必要があります。これら2つは別の問題です。
あなたは、ページのリロードがデータベースへの新しいクエリを引き起こしていると述べました。また、データベースは時々更新され、更新が必要なときにページにタイムリーに表示したい場合にも言及します。クエリのオーバーヘッドを減らす最善の方法は、クエリを実行しないことです。同じクエリを何度も実行して同じ結果が得られる場合は、しばらくの間それらをキャッシュしないでください。プロジェクトの残りの部分を変更せずに、上流にキャッシュを実装できるはずです。 rest について読むことをお勧めします。 rdbmsまたはnosqlでプロジェクトを実装するかどうかに関係なく、このタイプのパフォーマンスに関する問題は、データベースにアクセスする必要のある回数を減らすことで最適に処理されます。同じレシピに対して60秒で100のリクエストがあるとします。 60秒間キャッシュすると、データベースに1回しかヒットしないため、パフォーマンスが100倍向上します。 nosqlに切り替えることで同じレベルの改善を確認するには、さらに多くの作業が必要になります。
Nosqlタイプのシステムは、大量のデータがある場合や、極端な読み取りまたは書き込み速度の要件がある場合に、優れたソリューションになる可能性があります。ただし、その余分なパフォーマンスは、参照整合性などを破棄することを犠牲にしています。
実験または知識の目的でGraph-DBを試してみたいと思われますが、この例はノードをドリルダウン/アップできる階層データの例です。私はGraph/Neo DBの専門家ではありませんが、ユーザー/ユーザーがこのスキーマからデータを要求する方法はそれほど複雑ではありません。データベース/スキーマの設計の選択は、それに対してどのように、そしてどのタイプのデータが照会されるかに大きく依存していると思います。 SQLSERVER "HierarchyI" Dを使用しているので、このノードをツリーの一部として配置するには、私の観点からの最良のオプションです。
私の提案は、人間ではなく機械のように考えることです。繰り返しのように見えるかもしれませんが、それはどのマシンが得意かということです。自分に尋ねなければならないことの1つは、「ページに表示するために、とにかくすべてのオブジェクトを取得する必要がありますか?」ということです。はいの場合、データの取得と比較して、実行中の処理を続行します。単純な計算を行う場合、CPUサイクルは無視できます。