Linq System.OutofMemoryException

Cra*_*Ste 4 c# sql linq memory database-performance

我在C#中有一个长时间运行的进程,可以在10到200次的任何时间内访问Sql表.当进程超过大约50次命中并且每次从同一个表中查询大于大约100,000行时,它将在此行引发系统内存异常,特别是在它将IQuery对象转换为List的底部:

var cht = from p in _db.TickerData
          where p.Time >= Convert.ToDateTime(start) &&
          p.Time <= Convert.ToDateTime(end)
          orderby p.Time
          select p;

_prices = cht.ToList();    < this is where the System.OutofMemoryException occurs >
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能防止这个错误?

Mas*_*ler 6

首先:

特别是在底部,它将 IQuery 对象转换为列表

是的,这就是您期望发生内存不足情况的地方。

上面的赋值cht实际上并没有触及数据库;它所做的只是声明查询的形状。这称为延迟执行,LINQ 到处都使用它。这意味着“在您的代码需要之前,我们实际上不会处理任何内容。”

不过,调用ToList本质上是说“代码现在需要它,全部”。因此,它将查询发送到数据库,一次性提取所有结果,使用 LINQ 魔法将它们转换为 CLR 对象,然后将它们全部填充到 a 中List<T>

话虽如此,这只是一种预感,但您的 LINQ 提供程序可能不知道是什么Convert.ToDateTime。如果它不知道如何处理这个问题,它不会将其放入其执行的查询中的 WHERE 子句中,而是会加载整个表并在客户端进行过滤,这可能就是当变得太大,而不是当结果集变得太大时。

要验证这一点,请使用数据库的探查器来拦截查询,并查看 WHERE 子句是否符合您的预期。如果翻译不正确,请尝试以下操作:

var startTime = Convert.ToDateTime(start);
var endTime = Convert.ToDateTime(end);
var cht = from p in _db.TickerData
          where p.Time >= startTime && p.Time <= endTime
          orderby p.Time
          select p;
_prices = cht.ToList();
Run Code Online (Sandbox Code Playgroud)

如果这没有帮助,那么您可能只是拉回了太多数据,并且您必须像在任何其他上下文中处理太多数据一样进行处理。


Mak*_*kin 5

您尝试检索的数据对于您的列表来说太大了.ToList()出现异常,因为它正是执行查询的地方.用这么大的名单你想要达到什么目的?可能的解决方案是

1)使用更多条件限制搜索.加载不是整个数据,而是加载它的一部分,如果你真的需要,则加载另一部分.

2)如果要在内存中加载整个数据,请使用除列表之外的其他数据结构,请查看ConcurrentDictionary