gpt4 book ai didi

c# - 使用 EF Core FAST 读取数千个对象

转载 作者:IT王子 更新时间:2023-10-29 06:32:12 26 4
gpt4 key购买 nike

我正在使用 EF 核心从 SQLite 读取 40,000 个小对象/行,这需要 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 秒。

最佳答案

大多数答案都遵循加载较少数据的常识,但在某些情况下,例如此处您绝对肯定必须加载大量实体​​。那我们该怎么做呢?

性能不佳的原因

这么长时间的操作是不可避免的吗?好吧,它不是。我们只从磁盘加载 1 兆字节的数据,性能不佳的原因是数据被拆分成 40,000 个微小的实体。数据库可以处理这些,但 Entity Framework 似乎很难设置所有这些实体、更改跟踪等。如果我们不打算修改数据,我们可以做很多事情。

我尝试了三件事

原语

只加载一个属性,然后你会得到一个基元列表。

List<double> dataPoints =  _db.DataPoints.Select(dp => dp.Value).ToList();

这会绕过通常由 Entity Framework 执行的所有实体创建。此查询耗时 0.4 秒,而原始查询耗时 18 秒。我们说的是 45 (!) 倍的改进。

匿名类型

当然大多数时候我们需要的不仅仅是一个基元数组我们可以在 LINQ 查询中创建新对象。 Entity Framework 不会创建它通常会创建的实体,并且操作运行得更快。为了方便起见,我们可以使用匿名对象。

var query = db.DataPoints.Select(dp => new {Guid ID = dp.sensorID, DateTimeOffset Timestamp = dp.TimeStamp, double Value = dp.Value});

此操作需要 1.2 秒,而通常检索相同数量的数据需要 18 秒。

元组

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

var query = db.DataPoints.Select(dp => Tuple.Create(dp.sensorID, dp.TimeStamp, dp.Value));

其他方式

  1. 您不能在 LinQ 查询中使用结构,所以那不是选项
  2. 在许多情况下,您可以将许多记录组合在一起以减少与检索许多单独记录相关的开销。经过检索较少的较大记录可以提高性能。为了例如在我的用例中,我有一些测量值每 5 分钟拍摄一次,全天候 24/7。目前我正在储存它们单独,那是愚蠢的。没有人会查询少于他们一天的值(value)。我计划在进行更改时更新这篇文章并找出性能如何变化。
  3. 有些人建议使用面向对象的数据库或微型 ORM。我有两者都从未使用过,所以我无法发表评论。

关于c# - 使用 EF Core FAST 读取数千个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35854862/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com