Linq查询blob列表,内存占用

Linq query list of blob, memory usage

各位开发者大家好,

我正在尝试使用 Linq 查询改进以 BLOB 格式存储在 Oracle 数据库中的 XML 个对象列表的导出。

遗憾的是,其中一个 BLOB 非常大,当我读取它时内存使用量增长到 2 GB。我的 fileSet 对象是一个 IQueryable<myRecord> 对象。 我试过了

foreach (var file in fileSet){...}

var files = fileSet.ToList(); //This time the list is causing the memory load.
foreach(file in files){...}

var e = fileSet.AsEnumerable().GetEnumerator();
while(e.MoveNext()){...}

但是每次我在列表中打大记录时,内存都用完了。 为了创建导出,我一直在寻找一些使用 Buffer.BlockCopy 的代码,但是由于内存过载,如果您知道如何减少内存使用或延迟加载每个,则没有必要朝这个方向前进斑点:(

有几种解决方案: 1)将 AsNoTracking() 添加到您的查询中。

fileSet.AsNoTracking() or fileSet.AsNoTracking().Where(...) 

AsNoTracking() 帮助垃圾收集器释放记录,因为记录不会缓存在数据库上下文中。但如您所知,它不会立即起作用,您仍然可能会局部增加消耗的内存。

2) 您可以创建一个不包含 blob 字段的记录的单独定义,并通过它获取文件列表或使用 select 表达式它也可能有帮助,但您应该检查它是如何实现的被翻译成 sql

fileSet.AsNoTracking().Select(x=>new { x.Id, x.Name })

然后处理每条记录你将明确得到一个 blob

var myblob = model.Database
    .SqlQuery<string>("select myblob from mytable where id=@id", 
         new SqlParameter("@id", System.Data.SqlDbType.Int) { Value = myId })
    .FirstOrDefault();

var myBlob = fileSet
       .AsNoTracking()
       .Select(x=>new { x.Blob )
       .FirstOrDefault(x=>x.ConfigId=myId);

最后,因为我无法使用 linq 在内存中存储一​​些简单的东西,所以我使用 OracleCommand 来流式传输 xml 文件,在我得到文件的 ID 之后linq.

using (var reader = cmd.ExecuteReader())
{
   while (reader.Read())
   {
      var blob = reader.GetOracleLob(0);
      var buffer = new byte[128];
      using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Write))
      {
          blob.CopyTo(fs);
      }
   }
}