3

有人可以帮助我了解硬盘搜索的工作原理吗?

我有一个小的二进制数据库文件,它的读取性能是绝对必要的。如果我需要跳过文件中的几个字节,使用 seek() 还是 read() 会更快,然后丢弃不需要的数据。

如果硬盘的平均寻道时间为 10ms,读取速度为 300MB/s,我计算出 read() 比值小于 3MB 的 seek() 更快。是真的?执行新搜索时是否有开销,而读取现有流没有?

您认为哪种文件结构更适合索引。

Entry1:Value:PointerIntoToData
Entry2:Value:PointerIntoToData
Entry3:Value:PointerIntoToData
Data, Data, Data

Or

Entry1:Value:Data
Entry2:Value:Data
Entry3:Value:Data

读取条目时,如果值不正确,它将被忽略。因此,当流式传输文件时,它更快: 1. 当不需要条目时使用 seek() 跳过它 2. 当不需要条目时读取它然后丢弃数据 3. 或使用第一个结构,当最后需要将 seek() 输入到数据存储库中。

条目是 4 个字节,值是 8 个字节,数据是 12KB

干杯

4

4 回答 4

4

所有seek系统调用所做的就是改变文件中下一次读取的位置。它不移动驱动头。当读取或写入数据时,驱动器磁头会移动,并且您无法直接控制操作系统接下来会做什么。

读取大量不需要的数据会产生影响,因为所有读取的数据都需要操作系统缓冲区中的空间,并导致旧数据被丢弃。因此,对大文件使用搜索将减少文件系统缓存的混乱。


我在下面写的所有内容都假设您无法将整个数据库放入内存中。如果可以,就这样做。阅读所有内容并尝试在文件末尾附加新的和更改的数据。不要担心浪费空间,只是偶尔做一些压缩。


如果您的数据库太大:

数据以块(或页)的形式读取和写入物理驱动器。同样,操作系统中磁盘 IO 的基本单位是页。如果操作系统从磁盘缓存数据,它也在整个页面中。因此,考虑是否需要使用 seek 或 read 向前移动几个字节是没有意义的。如果你想让它变得更快,你需要考虑磁盘 IO 的真正工作原理。

首先,nobugz 已经提到,参考的位置。如果您在每个操作中使用的数据在文件中的位置很接近,那么您的操作系统将需要读取或写入更少的页面。另一方面,如果您传播数据,则需要一次读取或写入许多页面,这总是很慢。

至于索引的数据结构。通常它们被组织为B-trees。它是一种数据结构,专门用于通过分页读取和写入有效地搜索存储在内存中的大量数据。

两种组织数据的策略都在实践中使用。例如,MS SQL Server 默认以第一种方式存储数据:数据单独存储,索引仅包含来自索引列的数据和文件中数据行的物理地址。但是,如果您定义聚集索引,那么所有数据都将存储在该索引中。所有其他索引将通过聚集索引键而不是物理地址指向数据。第一种方法更简单,但如果您经常基于聚集索引扫描数据范围,则另一种方法可能更有效。

于 2009-03-01T21:19:18.720 回答
3

寻求访问权有多“绝对必要”?您是否使用非最佳解决方案测试了您的应用程序?在该测试期间,您是否进行了基准测试以确定真正的瓶颈在哪里?如果你没有,你会对结果感到惊讶。

接下来,尝试不同的方法并比较运行时间。在不同的系统负载下进行测试(即,当系统空闲时(除了您的应用程序)和忙碌时)。

考虑到当一个新的、更快的硬盘具有不同的内部优化时,您基于当前硬盘的优化可能会变得不正确,从而将您的工作抛到窗外。

于 2009-03-01T20:21:24.617 回答
1

顺序读取总是比需要磁头查找(而不是位置查找)的读取要快。用于顺序读取的典型硬盘驱动器性能为 50-60 MB/秒,寻找将其降至最坏情况下约 0.4 MB/秒。一旦驱动头被定位,您基本上可以免费获得气缸中的数据。文件系统缓存通过从柱面预读取扇区来利用这一点。

但是,您无法控制数据在磁盘柱面上的位置。您也无法猜测驱动器的几何形状。请注意,当卷碎片化时,吞吐量会随着时间的推移而显着变差。您需要通过在内存中缓存数据来寻找性能。那时,您担心参考的位置。

于 2009-03-01T20:25:42.267 回答
0

您始终可以将文件映射到内存中,然后通过指针等访问它。这通常会使您的访问更简单更快捷。

于 2009-03-02T02:30:18.847 回答