2015-09-22 53 views
2

我一直在處理這個問題2天,我找不到解決方案。改進實體框架插入

using (TaxablePersonContext context = new TaxablePersonContext(this.ConnectionString)) 
{ 
    context.Configuration.AutoDetectChangesEnabled = false; 
    foreach(TaxablePerson p in persons) // Persons has always size 1000 
    { 
     // TaxablePerson has some other properties e.g. Name, VatId, Street,... 
     p.RecCreatedBy = "application name"; 
     p.RecCreatedOn = this.SynchronizationStartDateTime; 
     p.RecModifiedBy = "application name"; 
     p.RecModifiedOn = this.SynchronizationStartDateTime; 
     p.RecSyncDate = this.SynchronizationStartDateTime; 
     p.RecActive = true; 
    } 
    DateTime start1 = DateTime.Now; 
    context.TaxablePersons.AddRange(persons); 
    TimeSpan end1 = DateTime.Now.Subtract(start1); 

    DateTime start2 = DateTime.Now; 
    context.SaveChanges(); 
    TimeSpan end2 = DateTime.Now.Subtract(start1); 
} 

我花了將近10秒來插入1000條記錄和98秒來在SQL Server中插入10.000記錄。您能否請告知如何改進實體框架插入性能。我閱讀這篇文章Fastest Way of Inserting in Entity Framework,幷包括本文中提到的技巧,但仍插入非常緩慢。我需要插入260.000條記錄,需要52分鐘。我插入1000個批次,上面的代碼演示。數據從文件中讀取,當我打1000個記錄時,我會與數據庫進行同步。我還可以做些什麼?有些人提到使用時設置context.Configuration.AutoDetectChangesEnabled = false;性能從幾分鐘提高到接近幾秒。我錯過了什麼?我正在使用實體框架6.1.3。

+0

您還應該使用: context.Configuration.ValidateOnSaveEnabled = false; –

+0

@ K.J。謝謝你的設置,但它沒有什麼區別。 – broadband

+0

在'using':'context.Database.Log = s => Debug.Write(s);'後面添加這段代碼''並在'using'結尾檢查VS中的Output窗口。可能你會看到奇怪的東西 – Szer

回答

0

使用sql分析器,我發現Entity框架逐一發送查詢,例如,在這種情況下

INSERT INTO MyTable (id, name) VALUES (1, 'Bob') 
INSERT INTO MyTable (id, name) VALUES (2, 'Peter') 
INSERT INTO MyTable (id, name) VALUES (3, 'Joe') 

所以實際的SQL Server 1000個執行插入很慢 - 近10秒(雖然在交易的執行)。然後我構造了插入多個值 - 具有許多值的SQL,並插入1000條記錄需要5秒(50%更好 - 前10秒)。 Sql server有一個可以傳遞的sql參數的限制,這是2100,所以這是你用這種方法可以做的最好的。

private void MultiRecordsInsert(TaxablePersonContext context, List<TaxablePerson> personsToAdd) 
{ 
    List<SqlParameter> parameters = new List<SqlParameter>(); 
    string firstQuery = @"insert into TaxablePerson (c1, c2, c3) values "; 
    string query = firstQuery; 

    for (int i = 0; i < personsToAdd.Count; i++) 
    { 
    query += "(@c1" + i.ToString(); 
    query += ",@c2" + i.ToString(); 
    query += ",@c3" + i.ToString() + "),"; 
    parameters.Add(new SqlParameter("@c1" + i.ToString(), personsToAdd[i].c1)); 
    parameters.Add(new SqlParameter("@c2" + i.ToString(), personsToAdd[i].c2)); 
    parameters.Add(new SqlParameter("@c3" + i.ToString(), personsToAdd[i].c3)); 

    // table has 16 columns (I reduced here for simplicity) so: 2100/16 = 131, 
    // used 100 
    // 
    if (i % 100 == 0) 
    { 
     query = query.Substring(0, query.Length - 1); // remove last comma 
     context.Database.ExecuteSqlCommand(query, parameters.ToArray()); 

     query = firstQuery; 
     parameters = new List<SqlParameter>(); 
    } 
    } 

    if (parameters.Count > 0) // what is left 
    { 
    query = query.Substring(0, query.Length - 1); 
    context.Database.ExecuteSqlCommand(query, parameters.ToArray()); 
    } 
} 
+0

考慮使用[TVP](https://msdn.microsoft.com /en-us/library/bb675163(v=vs.110).aspx)s。我知道沒有限制。 – ieaglle

+0

@ieaglle會看看thnx。 – broadband