Vla*_*yan 4 .net c# asp.net sqlite entity-framework-core
我正在从带有EF核心的SQLite读取40,000个小对象/行,这花了18秒,对于我的UWP应用来说太长了。发生这种情况时,单个内核上的CPU使用率达到100%,但是磁盘读取速度约为1%。
var dataPoints = _db.DataPoints.AsNoTracking().ToArray();
Run Code Online (Sandbox Code Playgroud)
没有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; }
}
Run Code Online (Sandbox Code Playgroud)
问题:是否有更好的方法来装载这么多对象,还是我对这种性能水平感到困惑?
有趣的事实: x86花费11秒,x64花费18。“优化代码”节省了一秒钟。使用Async将执行时间推至30秒。
大多数答案遵循加载较少数据的常识,但是在某些情况下,例如您在这里,绝对肯定必须加载许多实体。那么我们该怎么做呢?
表现不佳的原因
这样的手术难免要花这么长时间吗?好吧,不是。我们仅从磁盘加载一兆字节的数据,性能不佳的原因是数据分散在40,000个微小实体中。数据库可以解决这个问题,但是实体框架似乎很难设置所有这些实体,进行更改跟踪等。如果我们不打算修改数据,则可以做很多事情。
仅加载一个属性,然后您将获得一个基元列表。
List<double> dataPoints = _db.DataPoints.Select(dp => dp.Value).ToList();
Run Code Online (Sandbox Code Playgroud)
这绕过了通常由实体框架执行的所有实体创建。该查询花费了0.4秒,而原始查询为18秒。我们说的是改善了45(!)倍。
当然,在大多数情况下,我们不仅需要一组原始数组,我们还可以在LINQ查询内部创建新对象。实体框架不会像通常那样创建实体,并且该操作运行得更快。为了方便起见,我们可以使用匿名对象。
var query = db.DataPoints.Select(dp => new {Guid ID = dp.sensorID, DateTimeOffset Timestamp = dp.TimeStamp, double Value = dp.Value});
Run Code Online (Sandbox Code Playgroud)
此操作需要1.2秒,而通常要检索相同数量的数据需要18秒。
我发现在我的情况下,使用元组而不是匿名类型可以提高性能,以下查询的执行速度大约快30%:
var query = db.DataPoints.Select(dp => Tuple.Create(dp.sensorID, dp.TimeStamp, dp.Value));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1017 次 |
| 最近记录: |