有效的方式传输许多二进制文件到SQL Server数据库
本文关键字:SQL Server 数据库 二进制文件 许多 方式 传输 有效 | 更新日期: 2023-09-27 18:06:46
我们需要一个Winforms应用程序从本地文件系统(或网络位置)读取数千个文件并将它们存储在数据库中。
我想知道加载文件的最有效方法是什么?总共可能有很多gb的数据。
File.ReadAllBytes
当前被使用,但随着计算机内存耗尽,应用程序最终锁定。
当前代码循环遍历包含用于读取二进制数据的文件路径的表:
protected CustomFile ConvertFile(string path)
{
try
{
byte[] file = File.ReadAllBytes(path);
return new CustomFile { FileValue = file };
}
catch
{
return null;
}
}
数据然后保存到数据库(SQL Server 2008 R2或2012)使用NHibernate作为ORM
首先,让我声明一下,我的知识是在。NET 4.0之前,所以这些信息可能已经过时了,因为我知道他们将在这方面进行改进。
不要使用File。ReadAllBytes读取大文件(大于85kb),特别是当您依次读取许多文件时。我再说一遍,不要。
使用流和BinaryReader之类的东西。用阅读来缓冲你的阅读。即使这听起来效率不高,因为您不会通过单个缓冲区来消耗CPU,但如果您使用ReadAllBytes来这样做,它根本不会像您发现的那样工作。
这样做的原因是因为ReadAllBytes读取字节数组中的整个内容。如果字节数组在内存中>85Kb(还有其他考虑因素,如数组元素的数量),它将进入大对象堆,这很好,但是,LOH不会移动内存,也不会对释放的空间进行碎片整理,因此,简化,这可能发生:
- 读取1GB文件,您在LOH中有1GB块,保存该文件。(无GC循环)
- 读取1.5GB的文件,您请求1.5GB的内存块,它进入LOH的末端,但是假设您得到一个GC周期,因此您之前使用的1GB块被清除,但现在您有一个2.5GB内存块,第一个1GB空闲。
- 读取一个1.6GB的文件,开始的1GB空闲块不起作用,所以分配器转到最后。现在你有一个4.1GB的内存块。
- 重复。
你正在耗尽内存,但你肯定没有真正使用它,碎片可能会杀死你。此外,如果文件非常大(我认为Windows 32位的进程空间是2GB?),您实际上可能会遇到真正的OOM情况。
如果文件不是有序的或相互依赖的,那么通过使用BinaryReader缓冲来读取它们的几个线程可能会完成这项工作。
引用:http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/learning-memory-management/memory-management-fundamentals
https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/如果你有很多文件,你应该一个一个地读。
如果你有大文件,并且数据库允许,你应该把它们一块一块地读入缓冲区,然后一块一块地写入数据库。如果您使用File.ReadAllBytes
,当文件太大而无法装入运行时内存时,您可能会得到OutOfMemoryException
。上限小于2gib,如果应用程序运行一段时间后内存被碎片化,则上限更小。