Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 极慢的EF启动-15分钟_C#_Sql Server_Entity Framework - Fatal编程技术网

C# 极慢的EF启动-15分钟

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

不久前,我创建了一个系统,在该系统中,用户可以使用自定义文件为某些对象定义类别。然后,每个对象根据其类别具有FieldValue。以下类别:

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倍:

  • 将框架更新为6.2并启用:

    公共类CachingContextConfiguration:DbConfiguration { 公共CachingContextConfiguration() { SetModelStore(新的DefaultDbModelStore(Directory.GetCurrentDirectory()); }

    }

  • 尽早从新线程显式调用
    ctx.Database.Initialize()
    。这仍然需要3-4秒,但因为它与其他事情一起发生,所以帮助很大

  • 以合理的顺序将实体加载到EF缓存中

  • 之前,我只是在Inlude之后写了Include,它转换为多个连接。我在一些博客文章中发现了一条“经验法则”,即最多两条链式include-EF执行得相当好,但每一条都会大大降低速度。我还发现了一个,显示了EF缓存:一旦给定的实体加载了Include或Load,它将自动放入适当的属性中(blog作者关于对象的并集是错误的)。所以我这样做了:

      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;
    
  • 其影响几乎不明显,但可能在庞大的数据集上发挥更大的作用

    我还观看了Rowan Miller的EF Core演示,我将在下一版本中切换到它——在某些情况下,它比EF6快5-6倍


    希望这对某人有所帮助

    .ToArray()是您的问题。为什么不将其用作
    IQueryable
    ?因为我想要所有对象供以后在另一个对数据库的查询中使用?您想要所有对象吗?难道没有更好的方法来组织逻辑,使其不那么消耗资源和缓慢吗?我想要所有对象,是的。如果以后在工作站上一切都很快,我可以忍受启动缓慢(因为这是一项服务)。但16分钟是放慢速度的好办法。提到的带过滤器的搜索必须检查每个字段值,这意味着查询整个数据库(几乎是,因为大多数搜索都没有过滤器)。目前,即使有超过70k的记录,搜索也是即时的。如果每次查询DB,每次搜索都需要15分钟。这并不是说需要大量资源,而是在1GB内存下加载整个数据库。我认为单独加载所有实体并依靠关系修复来设置引用和集合会更好。包含在多个级别中的所有查询都必须非常庞大。这些步骤将大型数据库的加载时间从12分钟缩短到1分钟以下。
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;