C# 极慢的EF启动-15分钟
不久前,我创建了一个系统,在该系统中,用户可以使用自定义文件为某些对象定义类别。然后,每个对象根据其类别具有FieldValue。以下类别:C# 极慢的EF启动-15分钟,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,不久前,我创建了一个系统,在该系统中,用户可以使用自定义文件为某些对象定义类别。然后,每个对象根据其类别具有FieldValue。以下类别: public class DbCategory { public int Id { get; set; } [Required] public string Name { get; set; } [Required] public TextDbField MainF
public class DbCategory
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public TextDbField MainField { get; set; }
public List<DbField> Fields { get; set; }
}
public class DbObject
{
public int Id { get; set; }
public byte[] Bytes { get; set; }
[Required]
public DbCategory Category { get; set; }
public TextDbFieldValue MainFieldValue { get; set; }
public List<DbFieldValue> FieldsValues { get; set; }
}
public abstract class DbField
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool Required { get; set; }
}
public class IntegerDbField : DbField
{
public int? Minimum { get; set; }
public int? Maximum { get; set; }
}
public class FloatDbField : DbField
{
public double? Minimum { get; set; }
public double? Maximum { get; set; }
}
//... few other types
public abstract class DbFieldValue
{
[Key]
public int Id { get; set; }
[Required]
public DbField Field { get; set; }
[JsonIgnore]
public abstract string Value { get; set; }
}
public class IntDbFieldValue : DbFieldValue
{
public int? IntValue { get; set; }
public override string Value
{
get { return IntValue?.ToString(); }
set
{
if (value == null) IntValue = null;
else IntValue = int.Parse(value);
}
}
}// and other FieldValue types
我这样做是为了把一切都载入记忆。然后,我处理缓存列表并将更改写入数据库。我这样做是因为用户可以对每个字段值使用过滤器执行搜索。事实证明,每次查询数据库的速度都很慢,但这一部分工作得很好
问题会在以后发生。有些客户端定义了6个类别,每个类别上有20多个字段,并存储70k+条记录,启动有时需要15分钟以上。之后,5公里和50公里之间的速度没有差别
我发现的每一种提高EF代码首次启动时间的技术都主要考虑视图创建缓存、ngening EF等,但在这种情况下,在添加更多记录后,启动时间会增加,而不是添加更多实体类型
我意识到这是由模式的复杂性造成的,但是有什么方法可以加速这一过程吗?幸运的是,这是一个Windows服务,所以一旦启动,它将持续数周,但仍然是
我是否应该在第一次加载时删除EF并在纯SQL中执行它?我应该分批做吗?我应该把EF换成nHibernate吗?还是别的什么?在执行这一行的过程中,在虚拟化服务器上,该程序会使CPU达到最大值(不是SQL server,而是我的应用程序)
我尝试过只加载对象,然后稍后再加载它们的属性。这在小型数据库上要快一点(但不明显),但在大型数据库上更慢。感谢您的帮助,即使答案是“接受它并等待”。我通过这些技巧将EF的总启动时间缩短了3倍:
ctx.Database.Initialize()
。这仍然需要3-4秒,但因为它与其他事情一起发生,所以帮助很大 using (var db = new MyContext())
{
db.Fields.Load();
db.Categories.Include(c => c.MainField).Include(x => x.Fields).Load();
db.FieldValues.Load();
return db.Objects.Include(x => x.MainFieldValue.Field).ToArray();
}
这比从问题中获取数据快6倍。我认为,一旦以前加载了实体,EF引擎就不会为相关对象调用数据库,它只是从缓存中获取它们
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
希望这对某人有所帮助
.ToArray()代码>是您的问题。为什么不将其用作IQueryable
?因为我想要所有对象供以后在另一个对数据库的查询中使用?您想要所有对象吗?难道没有更好的方法来组织逻辑,使其不那么消耗资源和缓慢吗?我想要所有对象,是的。如果以后在工作站上一切都很快,我可以忍受启动缓慢(因为这是一项服务)。但16分钟是放慢速度的好办法。提到的带过滤器的搜索必须检查每个字段值,这意味着查询整个数据库(几乎是,因为大多数搜索都没有过滤器)。目前,即使有超过70k的记录,搜索也是即时的。如果每次查询DB,每次搜索都需要15分钟。这并不是说需要大量资源,而是在1GB内存下加载整个数据库。我认为单独加载所有实体并依靠关系修复来设置引用和集合会更好。包含在多个级别中的所有查询都必须非常庞大。这些步骤将大型数据库的加载时间从12分钟缩短到1分钟以下。
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;