C/C++的数据库写入与磁盘I/O
Database Write vs. Disk I/O For C/C++
所以我正在为一个新项目生成工作流。在第一阶段,将有一个生成大量数据的C/C++代码(基于测试用例的二进制文件格式,大约1TB)。然后,这些数据将被导入数据库,以便与驻留在那里的另一个数据集进行比较。
我的问题是,打开数据库软件的端口并直接写入,还是磁盘写入许多小文件(约10亿)并稍后导入数据库会更快?C代码将在有时间限制的集群上运行,因此需要快速完成。
虽然正确答案应该是"取决于情况,您需要测量",但在这种情况下,可以给出具有可接受确定性的不合格答案:
与数据库服务器直接对话几乎肯定会更快。
原因不仅在于先写入磁盘,然后在通过网络发送数据之前再次读取数据,这涉及到磁盘驱动器的额外延迟和带宽限制(这是不可避免的,因为每个文件在页面缓存中至少占用一个页面,十亿个文件——即使每个文件只有1字节的内容——也需要至少4TiB的缓冲区,因此不会有缓存)。假设在快速磁盘上按顺序读取,读取4TiB的数据需要3-5个小时。虽然由于延迟写回,向磁盘写入实际上可能主要是按顺序进行的,但在发送数据之前再次读取数据几乎可以保证不会是连续的(而且不存在提前读取的情况,这对于不同的文件来说是不可能的)。如果幸运的话,有些操作可能仍然是重叠的,隐藏了它们的延迟——但总的来说,这并不是"免费的"。
虽然确实,您可能会受到数据库接受请求的能力或网络带宽的限制,但这是您总是受到的限制,即使您没有添加额外的副本,至少前者是您可以很容易地优化的。您可以在没有任何索引的情况下将数据插入数据库,这将非常快速。然后,数据库服务器可以创建您以后可能需要的任何incides。当然,这可能需要一些时间,但这可能比每次更新指数快一个数量级(此外,谁在乎呢,如果重要的是你的限时工作完成得快的话)。
然而,更重要的是,仅仅打开、关闭和重新打开十亿个文件就需要非常显著的时间(这包括遍历目录层次结构、名称到索引节点的转换和访问检查等),而且访问单个文件所花费的时间将是非常疯狂的。即使在没有物理"查找"的固态磁盘上,随机访问时间也不是"零"(它们要小得多,但0.1毫秒乘以10亿仍然是几乎3个小时在查找上的额外花费!)。
您没有指定正在运行的数据库,所以理论上答案可能是任何东西。然而,在实践中,现代硬盘驱动器速度较慢:它们的写入速度约为100MB/s。通常,如果要向数据库中插入大量数据,这是一个限制因素。计算机中的RAM没有帮助,因为1TB无法放入RAM。但是,您可能需要使用特定于数据库的技巧,例如在单个事务中添加所有数据,以及可能编译一次并调用多次的预处理查询。如果你使用的是固态硬盘,答案可能会有所不同,但这取决于固态硬盘的速度。
请注意,网络接口可能会限制添加性能。千兆位链路实际上意味着略低于125 MB/s。因此,如果您的数据库在另一台计算机上,则网络接口性能可能是限制因素。然而,如果您在同一台计算机上或使用万兆链路生成数据,那么网络链路性能不太可能成为限制因素。
然而,唯一确定的答案是在你的环境中进行测试。如果绩效对你来说很重要,一定要学习基准测试的艺术。
这张表有索引吗?如果是这样的话,那么先插入数据,然后在插入所有数据后才构建索引可能会提高性能。
您必须对此进行测试才能知道。
不同的数据库产品以不同的速度运行,我们不知道数据库的硬件,如果在真正的大数据上有很多索引,可能会让一切变得缓慢。
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 根据 GetLastError 直接写入磁盘会导致错误代码 5
- 矢量和其他容器如何在磁盘上工作?
- 如何从整个磁盘中排除要装载的一个文件
- 如何将 IPropertyBag 保存到磁盘
- 防止临时对象文件访问 MSVC 中的磁盘
- 即使使用 FILE_FLAG_DELETE_ON_CLOSE 属性创建文件,文件也会保留在磁盘上
- Linux 源代码中普通磁盘文件的"轮询"功能在哪里实现?
- 文件删除(使用取消链接)与释放所有磁盘空间之间的延迟
- 在 Visual Studio 中调试时,是否可以将一些 C/C++ 结构内容保存到磁盘?
- 使用程序生成来创建磁盘,但纹理无法正常工作
- 使用C++项目将数据保存在磁盘上
- 将数据复制到磁盘上新位置的语法
- 通过C++与fst将对象写入R中的磁盘
- 如何使用PHP将上传到本地主机的一个html文件重定向到磁盘上的另一个html文档
- 磁盘已满时,Boost日志崩溃
- 使用大磁盘文件的 C++ 循环缓冲区
- 如何将 numpy 二维数组作为一种可以用C++读取的二进制格式存储在磁盘上
- 在磁盘上使用循环缓冲区
- 在数据写入磁盘之前,fwrite 会阻塞吗?