1

私の SQL と Entity Framework の知識はやや限られています。1 つの Entity Framework (4) アプリケーションで、メソッド呼び出しの 1 つを完了するのに永遠に (約 2 分) かかることに気付きました。最初のクエリにはそれほど時間はかかりませんが、クエリによって返された Entity Framework オブジェクトをループすると、取得したと思われるデータを読み取る (変更しない) だけであるにもかかわらず、ネストされたループを完了するのに永遠に時間がかかります。各リストには数十のエントリしかなく、数レベルのループがあります。

以下の例は、ループで実行しているすべてのフィルタリングと、実際には使用方法がわからないいくつかの SQL ワードを含む可能性のある、より洗練されたクエリで書き直すことができると思います。同等の SQL 式は、私にとって非常に教育的であり、おそらく現在のパフォーマンスの問題を解決します。

さらに、このアプリケーションや私が開発する他のアプリケーションの他の部分では、SQL データに対してより複雑な計算を実行する必要があることが多いため、Entity Framework からローカル メモリ オブジェクトにデータを取得し、読み取りに大きな遅延を生じさせない良い方法も知りたいと考えています。彼ら。私の LINQ-to-SQL プロジェクトでは、同様のパフォーマンスの問題がありました。アプリケーション全体をリファクタリングして、すべての SQL データを RAM 内の並列オブジェクトにロードすることで解決しましたが、これは自分で作成する必要がありました。 Entity Framework が実行している待機時間の長い通信を続行しないようにするか、ローカル RAM オブジェクトに読み込むように指示するより良い方法です。

以下の例では、コードは、SQL クエリを介して特定の日付のメンバー (つまり、人) のフード メニュー項目のリストを取得し、次に、他のクエリとループを使用して、2 つの基準でメニュー項目を除外します。 ) メンバーが、レシピがメンバーであるグループ ID (多対多の関係) に対してゼロの評価を持っている場合、および 2) メンバーがレシピ自体に対してゼロの評価を持っている場合。

例:

List<PFW_Member_MenuItem> MemberMenuForCookDate =
            (from item in _myPfwEntities.PFW_Member_MenuItem
             where item.MemberID == forMemberId
             where item.CookDate == onCookDate
             select item).ToList();

        // Now filter out recipes in recipe groups rated zero by the member:
        List<PFW_Member_Rating_RecipeGroup> ExcludedGroups =
            (from grpRating in _myPfwEntities.PFW_Member_Rating_RecipeGroup
             where grpRating.MemberID == forMemberId
             where grpRating.Rating == 0
             select grpRating).ToList();
        foreach (PFW_Member_Rating_RecipeGroup grpToExclude in ExcludedGroups)
        {
            List<PFW_Member_MenuItem> rcpsToRemove = new List<PFW_Member_MenuItem>();
            foreach (PFW_Member_MenuItem rcpOnMenu in MemberMenuForCookDate)
            {
                PFW_Recipe rcp = GetRecipeById(rcpOnMenu.RecipeID);
                foreach (PFW_RecipeGroup group in rcp.PFW_RecipeGroup)
                {
                    if (group.RecipeGroupID == grpToExclude.RecipeGroupID)
                    {
                        rcpsToRemove.Add(rcpOnMenu);
                        break;
                    }
                }
            }
            foreach (PFW_Member_MenuItem rcpToRemove in rcpsToRemove)
                MemberMenuForCookDate.Remove(rcpToRemove);
        }
        // Now filter out recipes rated zero by the member:
        List<PFW_Member_Rating_Recipe> ExcludedRecipes =
            (from rcpRating in _myPfwEntities.PFW_Member_Rating_Recipe
             where rcpRating.MemberID == forMemberId
             where rcpRating.Rating == 0
             select rcpRating).ToList();
        foreach (PFW_Member_Rating_Recipe rcpToExclude in ExcludedRecipes)
        {
            List<PFW_Member_MenuItem> rcpsToRemove = new List<PFW_Member_MenuItem>();
            foreach (PFW_Member_MenuItem rcpOnMenu in MemberMenuForCookDate)
            {
                if (rcpOnMenu.RecipeID == rcpToExclude.RecipeID)
                    rcpsToRemove.Add(rcpOnMenu);
            }
            foreach (PFW_Member_MenuItem rcpToRemove in rcpsToRemove)
                MemberMenuForCookDate.Remove(rcpToRemove);
        }
4

2 に答える 2

2

EFProf http://www.hibernatingrhinos.com/products/EFProfを使用して、EFがSQLに送信しているものを正確に追跡できます。また、送信しているクエリの数と一意のクエリの数を表示することもできます。また、各クエリの分析も提供します(たとえば、バインドされていないなど)。ナビゲーションプロパティを備えたEntityFrameworkは、dbリクエストを行っていることに気付かないのは非常に簡単です。ループに入っていて、ナビゲーションプロパティがある場合、N+1の問題が発生します。

于 2013-03-13T22:37:27.960 に答える
1

最初にコードを使用してプロキシを有効にしている場合は、モデルのリスト部分で Keyword Virtual を使用できます。これにより、必要なときにのみすべてのデータを一度に取得する必要がなくなります。

読み取り専用データの NoTracking も検討してください

context.bigTable.MergeOption = MergeOption.NoTracking; 
于 2013-03-13T22:18:34.980 に答える