2016-11-07 22 views
1

Entity Frameworkを使用して100個のエンティティ(およびその子要素)を大量に挿入しようとしています。ローカルホスト上にあるデータベースにバルクを挿入するのに約3秒かかり、同じイントラネット上にあるリモートデータベースに同じバルクを挿入しようとすると約300秒かかります。EF SaveChanges()はローカルホストでは非常に高速ですが、リモートデータベースでは非常に遅い

リモートデータベースとSaveChanges(ローカルホスト)を実行しているコンピュータとの間の接続は遅くありません。

私は、ファイアウォールやリモートSQLサーバー上の構成と関係があると推測しています。どうすれば問題をさらに調査することができますか?

これはコードです:

public void SaveProcessedProperties(object properties) 
    { 
     var propertiesToPersist = properties as List<Ejendom>; 

     using (var db = new TinglysUdv_UdpakEntities()) 
     { 
      db.Configuration.AutoDetectChangesEnabled = false; 
      db.Configuration.LazyLoadingEnabled = false; 

      try 
      { 
       foreach (var property in propertiesToPersist) 
       { 
        #region Haeftelse 
        if (property.Haeftelse.Any()) 
        { 
         foreach (var liability in property.Haeftelse) 
         { 
          if (liability.AttachDocument) 
          { 
           var existingDoc = db.Dokument.Find(liability.DokumentIdentifikator, liability.DokumentRevisionNummer); 

           if (existingDoc == null) 
           { 
            Dokument dbDoc; 
            if (DocumentExists(db, liability.DokumentIdentifikator, liability.DokumentRevisionNummer, out dbDoc)) 
            { 
             existingDoc = dbDoc; 
            } 
           } 

           if (existingDoc != null) 
           { 
            liability.Dokument = existingDoc; 
           } 
           else 
           { 
            var dok = new Dokument() 
            { 
             DokumentIdentifikator = liability.DokumentIdentifikator, 
             DokumentRevisionNummer = liability.DokumentRevisionNummer 
            }; 
            db.Dokument.Attach(dok); 
            liability.Dokument = dok; 
           } 
          } 
         } 
        } 
        #endregion 

        #region Adkomst 
        if (property.Adkomst.Any()) 
        { 
         foreach (var claim in property.Adkomst) 
         { 
          if (claim.AttachDocument) 
          { 
           var existingDoc = db.Dokument.Find(claim.DokumentIdentifikator, claim.DokumentRevisionNummer); 

           if (existingDoc == null) 
           { 
            Dokument dbDoc; 
            if (DocumentExists(db, claim.DokumentIdentifikator, claim.DokumentRevisionNummer, out dbDoc)) 
            { 
             existingDoc = dbDoc; 
            } 
           } 

           if (existingDoc != null) 
           { 
            claim.Dokument = existingDoc; 
           } 
           else 
           { 
            var dok = new Dokument() 
            { 
             DokumentIdentifikator = claim.DokumentIdentifikator, 
             DokumentRevisionNummer = claim.DokumentRevisionNummer 
            }; 
            db.Dokument.Attach(dok); 
            claim.Dokument = dok; 
           } 
          } 
         } 
        } 
        #endregion 

        #region Servitut 
        if (property.Servitut.Any()) 
        { 
         foreach (var easement in property.Servitut) 
         { 
          if (easement.AttachDocument) 
          { 
           var existingDoc = db.Dokument.Find(easement.DokumentIdentifikator, easement.DokumentRevisionNummer); 

           if (existingDoc == null) 
           { 
            Dokument dbDoc; 
            if (DocumentExists(db, easement.DokumentIdentifikator, easement.DokumentRevisionNummer, out dbDoc)) 
            { 
             existingDoc = dbDoc; 
            } 
           } 

           if (existingDoc != null) 
           { 
            easement.Dokument = existingDoc; 
           } 
           else 
           { 
            var dok = new Dokument() 
            { 
             DokumentIdentifikator = easement.DokumentIdentifikator, 
             DokumentRevisionNummer = easement.DokumentRevisionNummer 
            }; 
            db.Dokument.Attach(dok); 
            easement.Dokument = dok; 
           } 
          } 
         } 
        } 
        #endregion 

        db.Ejendom.Add(property); 
       } 

       db.SaveChanges(); 
      } 
      catch (Exception ex) 
      { 
       throw; 
      } 
     } 
    } 

private bool DocumentExists(TinglysUdv_UdpakEntities db, Guid documentIdentifier, int documentRevision, out Dokument dbDocument) 
{ 
    var documentExists = false; 

    dbDocument = db.Dokument.FirstOrDefault(x => x.DokumentIdentifikator == documentIdentifier && x.DokumentRevisionNummer == documentRevision); 

    if (dbDocument != null) 
    { 
     documentExists = true; 
    } 

    return documentExists; 
} 

Entity Framework Profilerのトレイル版を手に入れたし、コードをプロファイリング。ここでの結果は次のとおりです。

私は、次の警告を得た特定のコンテキストについては

enter image description here

INSERT [dbo].[Respekt] 
     ([RettighedIdentifikator], 
     [RespektServitutDato], 
     [Resp_Haeft_Fremtid_id]) 
VALUES ('1425fd57-042a-4649-a344-0f386b59e400' /* @0 - [RettighedIdentifikator] */, 
     NULL, 
     NULL) 

--////////////////////////////////////////////////// 

SELECT [Respekt_id] 
FROM [dbo].[Respekt] 
WHERE @@ROWCOUNT > 0 
     AND [Respekt_id] = scope_identity() 

は何があります:EFが作っているN + 1クエリの

例保存しようとしているエンティティの量を減らす以外に、私はこれについて行うことができますか?

+0

使用しているコードを表示できますか?それは、インサートがネットワーク上でより多くのオーバヘッドを引き起こすであろう一度に1つずつではなく、1つのことである可能性があります。 – Matthew

+0

私はコード – Kenci

+0

で質問を更新しました。ありがとうございました。私の考えが有効でないようにループを保存しているように見えます(同様の問題がありましたが、保存がループにありました)。この問題で幸運。 – Matthew

答えて

0

問題のある場所に近づくために、EFがSQL Management Studioから生成するSQLを実行します。その後、必要に応じてSQLプロファイラを実行できます。

あなたのコードがあるため遅くなることがあります:EFは、多くの個別のSQL文を生成し、それらのそれぞれが少し遅いです

  • 遅い

    1. 一つの大きなSQL。 < - それは私の推測です

    BTW。イントラネットで29ミリ秒のpingは非常に遅いです。

    var existingDoc = db.Dokument.Find(liability.DokumentIdentifikator, liability.DokumentRevisionNummer); はforeachの中に発行されます。www.stackoverflow.com

    +0

    申し訳ありませんが、私は自宅のコンピュータからVPNを介してイントラネットに接続しました。オフィスではなく、悪いです。私はオフィスからそれを実行するときSaveChangesの速度はまだ非常に遅いので、問題はまだ残っています。 pingとtracertのものを削除しました。 EFをプロファイリングして戻ってきます。前もって感謝します。 – Kenci

    +0

    最新の質問をご覧ください – Kenci

    0

    にpingを実行したときにあなたのコードがラインを介してすべてのループでデータベース呼び出しの多くを作っている大手検索プロバイダと5msのpingを実行するとき、私はそれより少ない取得しますこれらの呼び出しを最小限に抑える必要があります。

    あなたの代わりに、ループ内

    の元を、それを持つの1回の呼び出しですべてのオブジェクトを取得していることを行うことができます。代わりに

    foreach (var liability in property.Haeftelse) 
             { 
              if (liability.AttachDocument) 
              { 
               var existingDoc = db.Dokument.Find(liability.DokumentIdentifikator, liability.DokumentRevisionNummer); 
    } 
    

    あなたがすることができます

    var allLiabilities = db.Dokument.Where(a=> property.Haeftelse.Contains(a)) //you can adjust the condition exactly, ex: check on if AttachDocument = true 
    

    あなたがすべきこれを他のすべてのループに適用してください

    この方法では、ループごとに1つのクエリがあります。SaveChangesメソッドについては

    は、私はバルク

    に別のアプローチを更新する方法を知っているthis questionのための答えをチェックし、それがレコードごとに別々の挿入または更新ステートメントを発行します信じてストアドプロシージャを作成することです、合格ユーザ定義のテーブルタイプとしてレコードのリストを作成し、これらすべてのチェックをSQLで実行します

    関連する問題