使用Entity Framework和LINQ查询大型数据集时如何避免内存溢出

时间:2011-05-08 12:43:42

标签: c# linq entity-framework

我有一个处理所有数据库方法的类,包括与实体框架相关的东西。 当需要数据时,其他类可以调用此类中的方法,例如

public List<LocalDataObject> GetData(int start, int end);

数据库正在使用LINQ to EF进行查询,然后调用类可以迭代数据。 但由于其他类无法访问EF中的实体,因此我需要对查询执行“ToList()”操作,并将完整数据集提取到内存中。

如果此设置非常大(GB的10s-100s)会发生什么?

是否有更有效的迭代方法并仍然保持松耦合?

5 个答案:

答案 0 :(得分:19)

在Entity框架中使用大型数据集的正确方法是:

  • 使用EFv4和POCO对象 - 它将允许与上层共享对象而不会引入对实体框架的依赖
  • 关闭代理创建/延迟加载以完全从对象上下文中分离POCO实体
  • 公开IQueryable<EntityType>以允许上层更精确地指定查询并限制从数据库加载的记录数
  • 在您的数据访问方法中IQueryable MergeOption.NoTracking上展示ObjectQuery时。将此设置与关闭代理创建相结合应该导致不缓存的实体,并且通过查询结果的迭代应始终仅加载单个实体化实体(不缓存已加载的实体)。

在您的简单场景中,您始终可以检查客户端是否询问过多记录,只是触发异常或仅返回最大允许记录。

答案 1 :(得分:5)

尽管我喜欢EF用于快速/简单的数据访问,但我可能不会将它用于这种情况。在处理那个大小的数据时,我会选择能够准确返回你需要的存储过程,而不是额外的。然后使用轻量级DataReader填充对象。

  

DataReader提供无缓冲的   允许程序化的数据流   有效处理结果的逻辑   从数据源顺序。该   DataReader是一个不错的选择   检索大量数据   因为数据没有缓存   存储器中。

此外,就内存管理而言,当然要确保将代码处理非using块中的非托管资源包装起来,以便进行适当的处​​理/垃圾回收。

您也可以考虑实施paging

答案 2 :(得分:3)

关于这一点,请快速说明一下:

  

但由于其他课程无法访问   对于EF中的实体,我需要   执行“ToList()”操作   查询和通过获取完整   数据集到内存中。

我认为你遇到的问题根本与EF无关。如果你不使用EF进行数据访问而是使用原始ADO.NET,你会怎么做? “无法访问EF”转换为“无法访问数据库连接”

如果您的服务或方法必须使用大量对象但无法访问数据库(通过EF或其他类型的数据库连接),则必须先将数据加载到内存中,然后再将这些数据传递给这些服务/方法。然后,您可以考虑以某种方式在客户端的硬盘上缓冲加载的数据的解决方案,但这与数据源以及如何检索它们无关。如果不缓冲并将所有内容加载到内存中,则会受到可用内存的限制。我认为没有办法摆脱这种限制。

如果你有与EF的连接,我认为Ladislav的答案中提供的解决方案是正确的,因为他描述的设置和程序几乎将EF降低到简单的DataReader的行为。

答案 3 :(得分:0)

我会使用懒惰的IEnumerable并为你的数据实现某种分页。

也许创建你自己的IEnumerable接口,所以你的库的用户不要试图自己调用ToList。

但问题是......是否真的很好地隐藏了事实,这个数据层的用户可以使用这样的数据量?首先要做的是将返回的数据限制在最低限度。不要返回整个实体,而只返回您真正需要的部分。您是否渴望获取任何相关实体?你有没有想过使用延迟加载?

答案 4 :(得分:0)

可以肯定的一种方法是始终设置一个上限阈值,您将返回以通过.Take(MAX_ROWS)结束查询来避免巨大的设置。这可以是一种解决方法,也可以是一种预防措施,从一次糟糕的通话中取消您的服务,但最好是重新考虑解决方案