gpt4 book ai didi

c# - 使用 LINQ to SQL 读取大表 : Running out of memory vs slow paging

转载 作者:太空狗 更新时间:2023-10-29 22:10:59 25 4
gpt4 key购买 nike

我有一个巨大的表,我需要按特定顺序通读它并计算一些汇总统计信息。该表已经有一个正确顺序的聚集索引,因此获取记录本身非常快。我正在尝试使用 LINQ to SQL 来简化我需要编写的代码。问题是我不想将所有对象加载到内存中,因为 DataContext 似乎将它们保存在周围——但尝试对它们进行分页会导致可怕的性能问题。

这是分割。最初的尝试是这样的:

var logs = 
(from record in dataContext.someTable
where [index is appropriate]
select record);

foreach( linqEntity l in logs )
{
// Do stuff with data from l
}

这非常快,并且流式传输速度很快,但问题是应用程序的内存使用量不断增加,从未停止。我的猜测是 LINQ to SQL 实体被保存在内存中并且没有被正确处理。所以看完Out of memory when creating a lot of objects C# ,我尝试了以下方法。这似乎是许多人使用的常见 Skip/Take 范式,具有节省内存的附加功能。

请注意,_conn 是预先创建的,并且会为每个查询创建一个临时数据上下文,从而导致关联的实体被垃圾收集。

int skipAmount = 0;
bool finished = false;

while (!finished)
{
// Trick to allow for automatic garbage collection while iterating through the DB
using (var tempDataContext = new MyDataContext(_conn) {CommandTimeout = 600})
{
var query =
(from record in tempDataContext.someTable
where [index is appropriate]
select record);

List<workerLog> logs = query.Skip(skipAmount).Take(BatchSize).ToList();
if (logs.Count == 0)
{
finished = true;
continue;
}

foreach( linqEntity l in logs )
{
// Do stuff with data from l
}

skipAmount += logs.Count;
}
}

现在我有了所需的行为,即在我流式处理数据时内存使用量根本不会增加。然而,我有一个更糟糕的问题:每个 Skip 都会导致数据加载越来越慢,因为底层查询似乎实际上导致服务器遍历所有先前页面的所有数据。在运行查询时,每个页面的加载时间越来越长,我可以看出这正在变成二次运算。此问题出现在以下帖子中:

我似乎无法找到使用 LINQ 执行此操作的方法,该方法允许我通过分页数据限制内存使用,但仍然让每个页面在恒定时间内加载。有没有办法正确地做到这一点? 我的直觉是,可能有某种方法可以告诉 DataContext 明确忘记上述第一种方法中的对象,但我找不到如何做到这一点。

最佳答案

疯狂地抓了几根稻草后,我发现 DataContextObjectTrackingEnabled = false 可能正是医生所要求的。毫不奇怪,它是专门为这种只读情况设计的。

using (var readOnlyDataContext = 
new MyDataContext(_conn) {CommandTimeout = really_long, ObjectTrackingEnabled = false})
{
var logs =
(from record in readOnlyDataContext.someTable
where [index is appropriate]
select record);

foreach( linqEntity l in logs )
{
// Do stuff with data from l
}
}

上述方法在通过对象流式传输时不使用任何内存。写入数据时,我可以使用启用了对象跟踪的不同 DataContext,这似乎工作正常。然而,这种方法确实存在 SQL 查询的问题,它可能需要一个小时或更长时间才能流式传输和完成,因此如果有一种方法可以在不影响性能的情况下进行上述分页,我愿意接受其他替代方法。

关于关闭对象跟踪的警告:我发现当您尝试使用相同的 DataContext 进行多个并发读取时,您不会收到错误 已经有一个打开的 DataReader 与此 Command 关联,必须先将其关闭。 应用程序刚刚进入 CPU 使用率为 100% 的无限循环。我不确定这是 C# 错误还是功能。

关于c# - 使用 LINQ to SQL 读取大表 : Running out of memory vs slow paging,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12468219/

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