Performance Entityframework DbContext周围的泛型会导致性能下降吗?
我编写了一个简单的导入/导出应用程序,使用EntityFramework和AutoMapper从源->目标转换数据。它基本上是:Performance Entityframework DbContext周围的泛型会导致性能下降吗?,performance,entity-framework,generics,dbcontext,Performance,Entity Framework,Generics,Dbcontext,我编写了一个简单的导入/导出应用程序,使用EntityFramework和AutoMapper从源->目标转换数据。它基本上是: 从源表中选择记录的batchSize “映射源->目标实体中的数据” 将新的目标实体添加到目标表中,并保存上下文 我在不到5分钟的时间内移动了大约500k条记录。在我使用泛型重构代码后,性能在5分钟内急剧下降到250条记录 在DbContext上返回DbSet属性的我的委托是否导致了这些问题?还是发生了什么事? 快速非通用代码: 公共类导入器 { 公共
batchSize
DbContext
上返回DbSet
属性的我的委托是否导致了这些问题?还是发生了什么事?
快速非通用代码:
公共类导入器
{
公共无效导入地址()
{
常量int batchSize=50;
int done=0;
var src=new SourceDbContext();
var count=src.Addresses.count();
while(完成<计数)
{
使用(var dest=new DestinationDbContext())
{
var list=src.Addresses.OrderBy(x=>x.AddressId).Skip(完成).Take(batchSize.ToList();
list.ForEach(x=>dest.Address.Add(Mapper.Map(x));
完成+=批量大小;
dest.SaveChanges();
}
}
src.Dispose();
}
}
(非常)缓慢的通用代码:
公共类导入器
其中TSourceContext:DbContext
其中TDestinationContext:DbContext
{
公共无效导入(Func getSourceSet、Func getDestinationSet、Func getOrderBy)
其中TSourceEntity:class
where TDestinationEntity:类
{
常量int batchSize=50;
int done=0;
var ctx=Activator.CreateInstance();
//此getSourceSet委托是否可能导致问题?
//加上这个
var set=getSourceSet(ctx);
var count=set.count();
while(完成<计数)
{
使用(var dctx=Activator.CreateInstance())
{
var list=set.OrderBy(getOrderBy).Skip(done).Take(batchSize.ToList();
//或者数据库端分页机制是否被getSourceSet委托破坏?
//加上这个
var destSet=getdestinationstart(dctx);
ForEach(x=>destSet.Add(Mapper.Map(x));
完成+=批量大小;
dctx.SaveChanges();
}
}
ctx.Dispose();
}
}
问题是调用Func
委托您正在做很多事情。将结果值缓存在变量中,这样就可以了。问题是调用Func
委托,这是您经常做的事情。将结果值缓存在变量中,这样就可以了。我更改了通用代码(请参见//添加此代码),将变量用于Func
结果,但速度仍然很慢…它仍然在while
循环中。正确,由于缓存的原因,它需要在每个批处理后创建新的上下文。。否则对象会变得很大。您可以使用Detach
方法从上下文中删除处理过的对象。我更改了通用代码(请参见//添加此代码)以使用Func
结果的变量,但它仍然很慢…它仍然在而循环中。正确,由于缓存的原因,它需要在每个批处理之后创建一个新的上下文。。否则对象会变得很大。您可以使用Detach
方法从上下文中删除处理过的对象。为什么要在while块的每次迭代中创建新的目标实例?您可以使用while语句之外的内容移动该应用程序。请配置应用程序并确定!如果手头没有分析器,请暂停调试器10次。您可以在注释中提出问题,这些问题可以通过时间跟踪(秒表)轻松验证。为什么要在while块的每次迭代中创建新的目标实例?您可以使用while语句之外的内容移动该应用程序。请配置应用程序并确定!如果您手头没有分析器,请暂停调试器10次。您可以在注释中提出问题,这些问题可以通过时间跟踪(秒表)轻松验证。
public class Importer
{
public void ImportAddress()
{
const int batchSize = 50;
int done = 0;
var src = new SourceDbContext();
var count = src.Addresses.Count();
while (done < count)
{
using (var dest = new DestinationDbContext())
{
var list = src.Addresses.OrderBy(x => x.AddressId).Skip(done).Take(batchSize).ToList();
list.ForEach(x => dest.Address.Add(Mapper.Map<Addresses, Address>(x)));
done += batchSize;
dest.SaveChanges();
}
}
src.Dispose();
}
}
public class Importer<TSourceContext, TDestinationContext>
where TSourceContext : DbContext
where TDestinationContext : DbContext
{
public void Import<TSourceEntity, TSourceOrder, TDestinationEntity>(Func<TSourceContext, DbSet<TSourceEntity>> getSourceSet, Func<TDestinationContext, DbSet<TDestinationEntity>> getDestinationSet, Func<TSourceEntity, TSourceOrder> getOrderBy)
where TSourceEntity : class
where TDestinationEntity : class
{
const int batchSize = 50;
int done = 0;
var ctx = Activator.CreateInstance<TSourceContext>();
//Does this getSourceSet delegate cause problems perhaps?
//Added this
var set = getSourceSet(ctx);
var count = set.Count();
while (done < count)
{
using (var dctx = Activator.CreateInstance<TDestinationContext>())
{
var list = set.OrderBy(getOrderBy).Skip(done).Take(batchSize).ToList();
//Or is the db-side paging mechanism broken by the getSourceSet delegate?
//Added this
var destSet = getDestinationSet(dctx);
list.ForEach(x => destSet.Add(Mapper.Map<TSourceEntity, TDestinationEntity>(x)));
done += batchSize;
dctx.SaveChanges();
}
}
ctx.Dispose();
}
}