实体框架核心遍历大型Blob数据而不会导致内存溢出,这是最佳做法

我正在编写遍历大量图片数据的代码,准备了一个大的delta块,其中包含所有压缩后的数据以进行发送。

以下是有关此数据可能如何的示例

[MessagePackObject]
public class Blob : VersionEntity
{
    [Key(2)]
    public Guid Id { get; set; }
    [Key(3)]
    public DateTime CreatedAt { get; set; }
    [Key(4)]
    public string Mediatype { get; set; }
    [Key(5)]
    public string Filename { get; set; }
    [Key(6)]
    public string Comment { get; set; }
    [Key(7)]
    public byte[] Data { get; set; }
    [Key(8)]
    public bool IsTemporarySmall { get; set; }
}

public class BlobDbContext : DbContext
{
    public DbSet<Blob> Blob { get; set; }

    protected override void OnmodelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blob>().HasKey(o => o.Id);
    }
}

使用此功能时,我会将所有内容处理到一个文件流中,并且我希望在任何给定时间尽可能少地保留在内存中。

这样足以做到吗?

foreach(var b in context.Where(o => somefilters).AsnoTracking())
    MessagePackSerializer.Serialize(stream,b);

这将仍然用所有blob记录填充内存,还是在我对枚举器进行迭代时将它们一一处理。它不使用任何ToList,仅使用枚举器,因此Entity Framework应该可以随时处理它,但是我不确定那是否是它的作用。

这里的任何实体框架专家都可以为如何正确处理提供一些指导。

jun8888888 回答:实体框架核心遍历大型Blob数据而不会导致内存溢出,这是最佳做法

通常,当您在实体上创建LINQ筛选器时,就像以代码形式编写SQL语句一样。它返回尚未对数据库实际执行的IQueryable。当您使用IQueryable遍历foreach或调用ToList()时,将执行sql并返回所有结果,并将其存储在内存中。

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution

虽然EF可能不是纯粹性能的最佳选择,但有一种相对简单的方法来处理此问题,而不必过多担心内存使用情况:

请考虑以下内容

var filteredIds = BlobDbContext.Blobs
                      .Where(b => b.SomeProperty == "SomeValue")
                      .Select(x => x.Id)
                      .ToList();

现在,您已经根据需要过滤了Blob,并针对数据库执行了此操作,但是只返回了内存中的Id值。

然后

foreach (var id in filteredIds)
{
    var blob = BlobDbContext.Blobs.AsNoTracking().Single(x => x.Id == id);
    // Do your work here against a single in-memory blob
}

大blob一旦完成,应该可以用于垃圾回收,并且不会耗尽内存。

很显然,您可以感知ID列表中的记录数,或者可以将元数据添加到第一个查询中,以帮助您决定如何优化该想法。

,

只要你直接像nottracking说明的那样使用它,它只会在你迭代时读取你获取和处理的部分,所以我的第一个假设是正确的。

本文链接:https://www.f2er.com/3111719.html

大家都在问