3

聞いたことはありませんが、人々はアプリケーションの問題を「N+1 問題」と呼んでいます。彼らは Linq to SQL ベースのプロジェクトを行っており、パフォーマンスの問題が誰かによって特定されました。よくわかりませんが、誰かが私を操縦できることを願っています。

彼らはオブジェクトのリストを取得しようとしているようで、その後の Foreach はあまりにも多くのデータベース ヒットを引き起こしています。

私が理解していることから、ソースの 2 番目の部分は forwach にのみロードされています。

したがって、読み込まれたアイテムのリスト:

var program = programRepository.SingleOrDefault(r => r.ProgramDetailId == programDetailId);

そして後で、このリストを利用します。

foreach (var phase in program.Program_Phases)
{
    phase.Program_Stages.AddRange(stages.Where(s => s.PhaseId == phase.PhaseId));
    phase.Program_Stages.ForEach(s =>
    {
         s.Program_Modules.AddRange(modules.Where(m => m.StageId == s.StageId));
    });
    phase.Program_Modules.AddRange(modules.Where(m => m.PhaseId == phase.PhaseId));
}

特定された問題は、「プログラム」にその子が含まれていることを期待していたようです。しかし、クエリで子を参照すると、プログラムがリロードされます。

program.Program_Phases

彼らは、プログラムが完全にロードされてメモリ内にあることを期待しています.profilderは、すべての結合が各「foreach」で呼び出されているプログラムテーブルを示しているようです.

これは理にかなっていますか?

(編集: このリンクを見つけました: linq to sql は関連付けられたエンティティを自動的に遅延ロードしますか? これは私の質問に答えるかもしれませんが、.. この奇妙な (x => x....). したがって、このリンクが答えである場合、つまり、クエリで「結合」する必要がある場合、それは可能ですか?)

4

2 に答える 2

5

ORM 用語では、「N+1 選択問題」は通常、ネストされたコレクション プロパティを持つエンティティがある場合に発生します。これは、遅延読み込みを使用するときにエンティティ データをメモリに完全に読み込むために必要なクエリの数を指します。一般に、クエリが増えると、クライアントからサーバーへのラウンドトリップが増え、サーバーがクエリを処理するために必要な作業が増えるため、パフォーマンスに大きな影響を与える可能性があります。

この問題を回避するためのさまざまな手法があります。Linq to SQL には詳しくありませんが、NHibernate は熱心なフェッチをサポートしており、場合によっては役立ちます。エンティティ インスタンス全体を読み込む必要がない場合は、射影クエリを実行することも検討できます。もう 1 つの可能性は、エンティティ モデルを変更して、コレクションがネストされないようにすることです。

于 2012-09-03T23:42:32.547 に答える
3

パフォーマンスの高いlinqの場合、最初に、実際に気になるプロパティを正確に計算します。linqのパフォーマンス面での利点の1つは、使用しないデータの取得を簡単に省略できることです(linqよりも優れたものをいつでも手動でコーディングできますが、linqを使用すると、作成せずにこれを簡単に行うことができます。毎回省略したもののわずかなバリエーションのための何百ものクラスでいっぱいのライブラリ)。

あなたは「リスト」を数回言います。同じリストを複数回再利用する場合にのみ、必要がない場合はリストを取得しないでください。そうしないと、一度に1つのアイテムを処理すると、99%の時間でパフォーマンスが向上します。

あなたが言うところの「素敵な」と「奇妙な」構文は、同じことを言うための異なる方法です。メソッドとラムダでしか表現できないものもありますが、他の形式は常にそのように表現できます。実際、コンパイル後です。とにかくのようなものfrom b in someSource where b.id == 21 select b.nameがコンパイルされます。someSource.Where(b => b.id == 21).Select(b => b.name)

どのエンティティをどのオブジェクトにロードするかを正確に定義するように設定できDataContext.LoadOptionsます(そして何よりも、さまざまな用途で非常に簡単に異なる方法で設定できます)。これにより、N+1の問題を解決できます。

または、適切なIDを自分で設定することで、既存のエンティティを更新したり、新しいエンティティを挿入したりする方が簡単な場合があります。

簡単ではない場合でも、場合によっては高速になることがあります。通常、私はこの選択が進む限り、より簡単に行ってパフォーマンスを忘れると言いますが、ここでパフォーマンスが懸念される場合(そしてあなたがそう言う場合)、それは2つのどちらがより良く機能するかを確認するためのプロファイリングを行うことができます。

于 2012-09-04T00:07:48.760 に答える