2016-07-20 34 views
2

正如我從具有上下文MICSYDBCONTEXT的數據庫向具有BRIA_REALDBCONTEXT的數據庫導入數據。針對導入優化實體框架查詢

由於在MICSYDBCONTEXT數據庫中有280'000條記錄,我看到只需要5個小時就導入10000條記錄,所以我非常需要某種優化我的查詢。我正在使用Entity Framework 6,並且作爲初級開發人員,我會很感激任何幫助。

using (var context = new MICSYDBContext()) 
{ 
    var Doc = context.DOCUMENTS.OrderBy(x => x.ID).Take(100); 

    try 
    { 
     using (var context2 = new BRIA_REALDBCONTEXT()) 
     { 
      Stopwatch sw = Stopwatch.StartNew(); 

      foreach (var item in Doc) 
      { 
       var DOC = new DLV_DOC(); 
       DOC.FOLDID = item.ID; 
       DOC.FOBJECT = 1; 
       DOC.FIO = 40;    
       DOC.FID = newId; 
       DOC.FACTIVE = "Y"; 
       DOC.FCODEWRT = 85; 
       DOC.FDOC_COUNT_ORIGINAL = 'N'; 
       DOC.FUSERINSERT = 85; 
       DOC.FMODULE = 1; 
       DOC.FSERVICE_TYPE = 1; 

       var micsysserviceName = context.DEFDOCTYPE.Where(x => x.ID == item.DOCTYPE).FirstOrDefault(); 

       if (micsysserviceName != null) 
       { 
       var service = context2.DLV_SSERVICE.Where(x => x.FNAME == micsysserviceName.NAME && x.FSERVICE_TYPE == 1).FirstOrDefault(); 

       if (service != null) 
       { 
        DOC.FSERVICE = service.FID; 
       } 
       } 
       else 
       { 
       DOC.FSERVICE = 1; 
       } 

       var personcorespondent = context2.UCM_PERSON.Where(x => x.FOLD_ID == item.DOCKORID.ToString()).FirstOrDefault(); 

       if (personcorespondent != null) 
       { 
       DOC.FPERSON = personcorespondent.FID; 
       } 
       else 
       { 
        DOC.FPERSON = 142; 
       } 

       DOC.FDATEDOC = item.DATA; 

       foreach (var docsteps in context.DOCMOVE.Where(x => x.DOCID == item.ID).OrderBy(x => x.DATA)) 
       {//СТъпка 
       DLV_DOC_STEP DLVSTEP = new DLV_DOC_STEP(); 
       DLVSTEP.FDOC = DOC.FID; 
       DLVSTEP.FOBJECT = 1; 
       DLVSTEP.FCODEWRT = 85; 


       var whofirst = context2.UCM_PERSON.Where(x => x.FOLD_ID == docsteps.WHOFIRST.ToString()).FirstOrDefault(); 
       if (whofirst != null) 
       { 
        DLVSTEP.FPERSON = whofirst.FID; 
       } 
       var whonext = context2.UCM_PERSON.Where(x => x.FOLD_ID == docsteps.WHONEXT.ToString()).FirstOrDefault(); 
       if (whonext != null) 
       { 
        DLVSTEP.FTOPERSON = whonext.FID; 
       } 

       context2.DLV_DOC_STEP.Add(DLVSTEP); 
       } 

       context2.DLV_DOC.Add(DOC); 
       i++; 
       Console.WriteLine("Added " +i + "DOC"); 
      } 
      context2.SaveChanges(); 

      Console.WriteLine("End of docs"); 
      Console.WriteLine(sw.Elapsed.Hours); 
      } 
     } 
     catch (Exception ex) 
     { 
      string s = ex.Message; 
      Console.WriteLine("Problem with record"); 
      Console.WriteLine(ex.Message); 
      Console.WriteLine(ex.StackTrace); 
      Console.WriteLine(ex.InnerException); 
     } 
     } 
+0

您想訂購28萬條記錄。這將需要一段時間。 –

回答

1

這個問題是很常見的,

我們可以把它分爲三個類別:

  • 添加VS的AddRange性能
  • 讀&數據庫往返
  • 寫&數據庫往返

添加VS的AddRange性能

Add方法將嘗試每次添加一個新的記錄,而唯一的AddRange做一次時間來檢測變化。每次檢測到更改可能需要幾分鐘的時間。

這個問題很容易解決,只需創建兩個列表,將實體添加到此列表中,並在末尾使用AddRange和列表。

var DLV_DOC_STEPS = new List<DLV_DOC_STEP>(); 
var DLV_DOCS = new List<DLV_DOC>(); 

foreach(...) 
{ 
    foreach(...) 
    { 
     DLV_DOC_STEPS.Add(DLVSTEP); 
    } 

    DLV_DOCS.Add(DOC); 
} 

context2.DLV_DOC_STEP.AddRange(DLV_DOC_STEPS); 
context2.DLV_DOC.AddRange(DLV_DOC); 
context2.SaveChanges 

另一種解決方案是在開始&調用SaveChanges之前&重新啓用它禁用AutoDetectChange。我建議第一個解決方案,但都工作。

ctx.Configuration.AutoDetectChangesEnabled = false; 
foreach(var item in Doc) 
{ 
    // ...code... 
} 

ctx.Configuration.AutoDetectChangesEnabled = true; 
ctx.SaveChanges(); 

讀&數據庫往返

應用程序正在執行太多的數據庫往返

您在下面的實體進行查詢多次:

  • DEFDOCTYPE
  • DLV_SSERVICE
  • UCM_PERSON
  • DOCMOVE

你執行數百萬數據庫往返這是瘋狂的,所以你的應用當然是很慢!

解決方案?

  • 首先嚐試加載所有數據,並使用一本字典,而不是擺脫記憶的實體(如表不包含太多的記錄)。

例子:

var defDoctTypeDict = context.DEFDOCTYPE.AsNoTracking().ToList().ToDictionary(x => x.ID); 

foreach(var item in Doc) 
{ 
    DEFDOCTYPE micsysserviceName; 

    defDoctTypeDict.TryGetValue(item.DOCTYPE, out micsysserviceName); 
    if(micsysserviceName != null) 
    { 
     // ...code... 
    } 

    // ...code... 
} 
  • 通過創建一個列表,並使用List.Contains代替 您可以閱讀有類似的問題在這裏有人加載批量數據:https://stackoverflow.com/a/38355262/5619143

  • 如果您不需要跟蹤實體,請使用AsNoTracking

寫&數據庫往返

每次你保存記錄,你執行一個數據庫往返。

免責聲明:我是這個項目的所有者Entity Framework Extensions

這個庫允許執行:

  • BulkSaveChanges
  • BulkInsert
  • BulkUpdate
  • BulkDelete
  • BulkMerge

您可以在批處理結束時調用BulkSaveChanges,也可以創建一個列表插入並直接使用BulkInsert,以獲得更高的性能。

BulkSaveChanges解決方案(辦法比的SaveChanges更快)

context2.DLV_DOC_STEP.AddRange(DLV_DOC_STEPS); 
context2.DLV_DOC.AddRange(DLV_DOC); 
context2.BulkSaveChanges 

BulkInsert解決方案(最快比BulkSaveChanges但不保存相關實體)

context2.BulkInsert(DLV_DOC_STEPS); 
context2.BulkInsert(DLV_DOC);