【问题标题】:How does the Entity Framework walks through a collection that is too big?实体框架如何遍历一个太大的集合?
【发布时间】:2012-10-12 06:05:46
【问题描述】:

我是实体框架的新手。

我有一个担心:

我需要遍历通过 LINQ to Entities 收集的大量数据,这些数据以匿名类型组合了来自不同实体的几个属性。

如果我需要一个一个地读取这个查询的返回项直到结束,我是否面临 OutOfMemory 异常的风险,因为集合是 BIG 或 EF 隐式使用 SqlDataReader?

(或者我应该使用 EntityDateReader 来确保我按顺序读取 Db(但是我猜我必须将查询生成为字符串))

【问题讨论】:

    标签: c# .net entity-framework sqldatareader


    【解决方案1】:

    据我所知,您可以做两件事,首先使用 .AsNoTracking 关闭跟踪,这在大多数情况下会将您的内存集减少一半,这可能就足够了。

    如果您的集合仍然太大,请使用 skip 和 take 以块的形式下拉结果集。您还应该将其与 AsNoTracking 结合使用,以确保跟踪不会消耗内存

    编辑:

    例如,您可以使用类似于以下内容的内容循环遍历 1000 个块中的所有项目。以下代码一次只能在内存中保存 1000 个项目。

    int numberOfItems = ctx.MySet.Count();
    
    for(int i = 0; i < numberOfItems + 1000; i+=1000)
    {
        foreach(var item in ctx.MySet.AsNoTracking().Skip(i).Take(1000).AsEnumerable())
        {
             //do stuff with your entity
        }
    }
    

    【讨论】:

    • 对不起;实际上,“使用跳过并以块的形式下拉结果集”是什么意思?
    【解决方案2】:

    如果数据量如您所说的那么大,我建议您不要在这种情况下使用 EF。 EF 很棒,但有时您需要回退并使用标准 SQL 以获得更好的性能。

    看看 Dapper.NET https://github.com/SamSaffron/dapper-dot-net

    如果您真的想在每种情况下都使用 EF,我建议您使用 Bounded Contexts(多个 DBContexts)。

    在多个较小的上下文中拆分模型将提高性能,因为当 EF 创建上下文的内存模型时,您将使用更少的资源。

    上下文越大,生成的资源就越多 并维护该内存模型。

    您还可以在共享多个上下文的实例时分离附加,这样您仍然不会加载所有模型。

    【讨论】:

    • 这实际上不是性能问题,但即使是这样,使用 dapper 这样的平台所带来的性能提升也没有您建议的那么大。使用大型数据集时,dapper 的批量选择性能比 EF 提高了大约 25%,但我认为这在计算方面相当微不足道。在此处查看我的性能统计数据:blog.staticvoid.co.nz/2012/03/entity-framework-comparative.html
    • 就实际内存使用而言,在没有跟踪的情况下,dapper 和 EF 之间的差异将非常小。我不太确定您对有界上下文的含义是什么,因为这是一个 DDD 术语,与性能或内存消耗无关,更关心逻辑分离。此外,通过将 detach 与 EF 一起使用来减少内存并不是一个好主意,因为当您调用 detach 时,您已经消耗了内存。 .AsNoTracking 在这里是一个更好的解决方案,因为它意味着内存永远不会分配给跟踪器。
    • 使用较小的上下文(按领域需求分开)会减少内存,因为 EF 在创建上下文的内存模型时会消耗更少。
    • 如果他必须处理相同数量的对象,无论他如何划分它都会占用相同数量的内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    相关资源
    最近更新 更多