Hello开发人员,
我正在尝试使用Linq查询改进在Oracle数据库中以BLOB格式存储的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()){...}
但是每当我打到列表中的大记录时,ram就会被过度使用。
为了创建导出,我正在寻找使用Buffer.BlockCopy
的一些代码但是由于内存过量充电,如果你有一些想法如何减少内存使用量或延迟加载,那么在这个方向上没有任何意义blob :(
答案 0 :(得分:1)
有几种解决方案: 1)将AsNoTracking()添加到您的查询中。
fileSet.AsNoTracking() or fileSet.AsNoTracking().Where(...)
AsNoTracking()帮助垃圾收集器释放记录,因为记录不会缓存在数据库上下文中。但是,正如您所知道的那样,它不会立即起作用,您可能会在本地消耗内存增加。
2)您可以创建一个单独的记录定义,该记录不包含blob字段并通过它获取文件列表或使用select表达式它也可能有帮助,但您应该检查它是如何转换为sql < / p>
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);
答案 1 :(得分:1)
最后因为我无法使用linq在内存中设置一些亮点,所以在使用linq获取文件的ID之后,我使用OracleCommand
来传输xml文件。
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);
}
}
}