生成されたクエリに1/2秒しかかからないのに、Entity Frameworkがレコードのロードに30秒かかるのはなぜですか?

.net c# entity-framework linq-to-entities

質問

以下のexecuteTimeは、最初の30秒、次に同じコードセットを実行したときの25秒です。 SQLプロファイラで見ているとき、私はすぐにログインを見ます、そしてそれはちょうど約30秒間そこに座っています。その後、selectステートメントが実行されるとすぐに、アプリケーションはToListコマンドを終了します。 Management Studioから生成されたクエリを実行すると、データベースクエリにかかる時間はわずか400ミリ秒です。 14行350列を返します。データベースの結果をエンティティに変換するのにかかる時間は非常に短いので、目立たないようです。

それでは、データベース呼び出しが行われる30秒前に何が起きているのでしょうか。

エンティティフレームワークがこれほど遅い場合は、それを使用することは不可能です。これを劇的にスピードアップするために、私が間違っていることや変更できることはありますか?

更新:大丈夫、私はコンパイルされたクエリを使用する場合、最初の時間は30秒かかり、二回目は1/4秒かかります。最初の通話をスピードアップするためにできることはありますか?

using (EntitiesContext context = new EntitiesContext()) 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    var groupQuery = (from g in context.Groups.Include("DealContract") 
                    .Include("DealContract.Contracts") 
                    .Include("DealContract.Contracts.AdvertiserAccountType1") 
                    .Include("DealContract.Contracts.ContractItemDetails") 
                    .Include("DealContract.Contracts.Brands") 
                    .Include("DealContract.Contracts.Agencies") 
                    .Include("DealContract.Contracts.AdvertiserAccountType2") 
                    .Include("DealContract.Contracts.ContractProductLinks.Products") 
                    .Include("DealContract.Contracts.ContractPersonnelLinks") 
                    .Include("DealContract.Contracts.ContractSpotOrderTypes") 
                    .Include("DealContract.Contracts.Advertisers") 
                where g.GroupKey == 6 
                select g).OfType<Deal>(); 
    sw.Stop(); 
    var queryTime = sw.Elapsed; 
    sw.Reset(); 
    sw.Start(); 
    var groups = groupQuery.ToList(); 
    sw.Stop(); 
    var executeTime = sw.Elapsed; 
} 

受け入れられた回答

私はこれと全く同じ問題を抱えていました、私の質問は40秒かかりました。

問題は.Include("table_name")関数にあることがわかりました。私が持っていたこれらが多いほど、それは悪化しました。代わりに、クエリ直後に必要なすべてのデータをLazy Loadにコードを変更しました。これにより、合計時間が40秒から約1.5秒に短縮されました。私の知る限りでは、これはまったく同じことを達成します。

だからあなたのコードのためにそれはこのようなものになるでしょう:

var groupQuery = (from g in context.Groups
            where g.GroupKey == 6 
            select g).OfType<Deal>(); 

var groups = groupQuery.ToList();

foreach (var g in groups)
{
    // Assuming Dealcontract is an Object, not a Collection of Objects
    g.DealContractReference.Load();
    if (g.DealContract != null)
    {
        foreach (var d in g.DealContract)
        {
            // If the Reference is to a collection, you can just to a Straight ".Load"
            //  if it is an object, you call ".Load" on the refence instead like with "g.DealContractReference" above
            d.Contracts.Load();
            foreach (var c in d.Contracts)
            {
                c.AdvertiserAccountType1Reference.Load();
                // etc....
            }
        }
    }
}

ところで、あなたはあなたの現在のコード内のクエリ上のコード行を追加した場合、それは私が理解約4-5秒(私のオプションではまだあまり玲)までの時間をノックう、 MergeOption.NoTrackingオプション無効更新してデータベースに挿入するための多くの追跡オーバーヘッド。

context.groups.MergeOption = MergeOption.NoTracking;

人気のある回答

これはインクルードのためです。私は、あなたがたくさんのオブジェクトをメモリにロードしようとしているのだと思います。 dbエンティティに対応するc#オブジェクトを構築するのは時間がかかります。

あなたへの私のお勧めは、必要なデータだけを遅延ロードすることです。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ