C# 使用EF Core快速读取数千个对象

C# 使用EF Core快速读取数千个对象,c#,asp.net,.net,sqlite,entity-framework-core,C#,Asp.net,.net,Sqlite,Entity Framework Core,我正在使用EF core从SQLite读取40000个小对象/行,这需要18秒,这对于我的UWP应用程序来说太长了。 当这种情况发生时,单个内核上的CPU使用率达到100%,但磁盘读取速度约为1% var dataPoints = _db.DataPoints.AsNoTracking().ToArray(); 没有AsNoTracking()所需的时间甚至更长 DataPoint是一个具有一些基本属性的小型POCO。我正在加载的数据总量为4.5 MB public class Da

我正在使用EF core从SQLite读取40000个小对象/行,这需要18秒,这对于我的UWP应用程序来说太长了。 当这种情况发生时,单个内核上的CPU使用率达到100%,但磁盘读取速度约为1%

var dataPoints =  _db.DataPoints.AsNoTracking().ToArray();
没有
AsNoTracking()
所需的时间甚至更长

DataPoint
是一个具有一些基本属性的小型POCO。我正在加载的数据总量为4.5 MB

    public class DataPointDto
    {
        [Key]
        public ulong Id { get; set; }

        [Required]
        public DateTimeOffset TimeStamp { get; set; }

        [Required]
        public bool trueTime { get; set; }

        [Required]
        public double Value { get; set; }
   }
问题:是否有更好的方法加载这么多的对象,或者我是否被这种性能水平所困扰


有趣的事实:x86需要11秒,x64需要18秒优化代码可以节省一秒钟的时间。使用
Async
将执行时间推到30秒

您可以使用不同的技术加载所有项目

您可以创建自己的逻辑,在用户滚动ListView时加载部分数据(我猜您正在使用它)

幸运的是,UWP是实现这一技术的简单方法。 增量荷载 请参阅文档和示例


大多数答案遵循加载较少数据的常识,但在某些情况下,例如在这里,您必须绝对积极地加载大量实体。那我们怎么做呢

性能不佳的原因

这次手术要花这么长时间是不可避免的吗? 嗯,不是。我们只从磁盘加载了1兆字节的数据,性能低下的原因是数据被分割到了40000个小实体中。数据库可以处理这个问题,但实体框架似乎很难设置所有这些实体、更改跟踪等。如果我们不打算修改数据,我们可以做很多事情

我试了三件事 原语 只加载一个属性,就可以得到一个原语列表

List<double> dataPoints =  _db.DataPoints.Select(dp => dp.Value).ToList();
此操作需要1.2秒,而通常检索相同数量的数据需要18秒

多元组 我发现在我的例子中,使用元组而不是匿名类型稍微提高了性能,以下查询的执行速度大约快了30%:

var query = db.DataPoints.Select(dp => Tuple.Create(dp.sensorID, dp.TimeStamp, dp.Value));
其他方式
  • 不能在LinQ查询中使用结构,因此这不是 选择权
  • 在许多情况下,您可以将多个记录组合在一起以减少 与检索多个单独记录相关的开销。通过 检索较少的较大记录可以提高性能。对于 例如,在我的用例中,我得到了一些正在进行的度量 每5分钟一次,24/7。目前我正在储存它们 单独的,那是愚蠢的。没有人会质疑不到一个小时 一天就够了。我计划在做出更改时更新此帖子 并了解性能是如何变化的
  • 有些人建议使用面向对象的DB或micro ORM。我有 也没用过,所以我不能评论

  • 对2600万条记录(1条datetime、1条double、1条int)进行性能测试,EF Core 3.1.5:

    • 接受答案中建议的匿名类型或元组=关于 20秒,1.3GB内存

    • 结构=大约15秒,0.8GB内存


    是否需要一次检索所有对象?或者你可以进行延迟加载吗?我必须一次检索所有图形。你的表上有索引吗?这可能会加快速度?你必须想一个不同的方法来解决这个问题。据我所知,SQLLite不支持存储过程。但你似乎可以使用CLR。(). 使用CLR函数只输出最基本的数据点来创建图形。我只是将整个表加载到内存中。我看不出索引或存储过程会有什么帮助。我错过什么了吗?制作更少的、更大的记录会提高性能吗?很好的技术。谢谢你的提示。
    var query = db.DataPoints.Select(dp => Tuple.Create(dp.sensorID, dp.TimeStamp, dp.Value));