2015-09-22 108 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