【发布时间】:2017-08-05 14:19:41
【问题描述】:
我试图请求大量数据,然后将其解析为报告。问题是我请求的数据有 2700 万行记录,每行有 6 个连接,当通过实体框架加载时会使用所有服务器 RAM。我已经实现了一个分页系统来将处理缓冲成更小的块,就像你对 IO 操作所做的那样。
我请求 10,000 条记录,将它们写入文件流(写入磁盘),我正尝试从内存中清除 10,000 条记录,因为它们不再需要。
我在垃圾收集数据库上下文时遇到了麻烦。我已经尝试处理对象,将引用清空,然后在下一批 10,000 条记录上创建新上下文。这似乎不起作用。 (这是 ef core 上的一位开发人员推荐的:https://github.com/aspnet/EntityFramework/issues/5473)
我看到的唯一其他选择是使用原始 SQL 查询来实现我想要的。我正在尝试构建系统来处理任何请求大小,唯一的可变因素是生成报告所需的时间。我可以用 EF 上下文做些什么来摆脱加载的实体吗?
private void ProcessReport(ZipArchive zip, int page, int pageSize)
{
using (var context = new DBContext(_contextOptions))
{
var batch = GetDataFromIndex(page, pageSize, context).ToArray();
if (!batch.Any())
{
return;
}
var file = zip.CreateEntry("file_" + page + ".csv");
using (var entryStream = file.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
foreach (var reading in batch)
{
try
{
streamWriter.WriteLine("write data from record here.")
}
catch (Exception e)
{
//handle error
}
}
}
batch = null;
}
ProcessReport(zip, page + 1, pageSize);
}
private IEnumerable<Reading> GetDataFromIndex(int page, int pageSize, DBContext context)
{
var batches = (from rb in context.Reading.AsNoTracking()
//Some joins
select rb)
.Skip((page - 1) * pageSize)
.Take(pageSize);
return batches
.Includes(x => x.Something)
}
【问题讨论】:
-
“数据”是什么意思?如果您对某种 DTO 对象使用投影查询,或者不使用跟踪查询,
DbContext将不会在内部存储任何内容。也不要使用ToList、ToArray等。只需枚举结果即可。 -
我已使用
.AsNoTracking()关闭查询的更改跟踪。我还删除了ToArray(),但垃圾收集器仍然没有释放任何上下文。 prntscr.com/g4q0h3 至于我所说的数据,我的意思是我希望将记录从数据库中获取到 C# 模型中,以便临时使用然后处理掉。我有一种感觉,由于递归循环,对象没有从内存中删除? -
不要使用 EF Core,这不是合适的情况。使用原始查询,您始终可以读取数据的子集,即使用数据阅读器
标签: c# entity-framework asp.net-core