[我遇到性能问题,同时尝试将c#与EF5和SQL Server 2012数据库(具有4gb RAM)一起使用,同时尝试插入数千个项目。
例如,这段代码使我在MVC应用程序中执行需要12秒钟的时间,而在Windows控制台应用程序中需要5秒钟的时间,因此context.saveChanges()
语句消耗了其中的99%。
//Prepare list
Random rand = new Random();
List<MyItem> list = new List<MyItem>();
for(int i = 0; i < 1000; i++) {
list.Add(new MyItem {
Field1 = i,
Field2 = rand.Next(1000),
Field3 = rand.Next(1000),
Field4 = rand.Next(1000),
Field5 = rand.Next(1000),
Field6 = rand.Next(1000),
Field7 = rand.Next(1000),
Field8 = rand.Next(1000),
Field9 = rand.Next(1000),
Field10 = rand.Next(1000)
});
}
Stopwatch watch = new Stopwatch();
Stopwatch watch2 = new Stopwatch();
watch.Start();
using (var context = new MyEntities())
{
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
foreach (MyItem item in list)
{
context.MyItem.Attach(item);
context.Entry(item).State = System.Data.EntityState.Added;
}
watch2.Start();
context.SaveChanges();
watch2.Stop();
}
watch.Stop();
我试图关闭AutoDetectChangesEnabled和ValidateOnSaveEnabled,但似乎没有性能提高。我也尝试了单个插入存储过程,但是性能与之相似。
表MyItem是具有十个整数字段和一个集群主键的简单表。
任何帮助将不胜感激!
我们可以仅从“实体框架没有批量插入”开始。它将生成零插入的插入语句。零-每行往返一次,它甚至不将多行放入语句中。在您的示例中,有1000条插入语句-而且还有1000条单独的服务器进程往返。
我已经为DbContext写了很长的扩展方法,使我可以使用签名为BulkInsert<T>(IEnumerable<T>)
或BulkMerge<T>(IEnumerable<T>)
的方法。大约5页代码。
T
类通常是手工制作的,以避免与EF实体重叠。我可以在一秒钟左右的时间里批量插入64000没问题。我主要将自己的对象数据读取器与SqlBUlkCopy类一起使用,以将数据推送到临时表中,然后将其插入或合并到最终表中-临时表避免了在上传过程中最终表上的排他锁以及不太聪明的锁定机制在SqlBulkCopy中。
但是对于批量插入使用纯EF-您可以在这里忘记性能。如果您在此处使用搜索,则会发现大量对此的投诉。 EF是ORM-它不是ETL工具。