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);
}
}
}
各位开发者大家好,
我正在尝试使用 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);
}
}
}