当需要存储一些 BLOB 信息时,可以将完整的文件内容直接存储在数据库中,也可以将其存储在单独的文件中并仅将相应的文件名存储在数据库中。这两种方式里,哪个的读取速度更快呢?
为了尝试回答这个问题,我运行了 49 个测试案例,其中有各种 BLOB 大小和 SQLite 页面大小。对于每个测试案例,我创建了一个包含 100MB BLOB 内容的数据库。BLOB 的大小从 10KB 到 1MB 不等。BLOB 的数量是不同的,以保持总的 BLOB 内容在100MB左右(因此,1MB 大小的 BLOB 为100 个,10K 大小的 BLOB为 10000 个,以此类推)。使用了 SQLite 3.7.8 版本。
下面的表格显示了读取存储在独立文件中的 BLOB 所需的时间除以读取完全存储在数据库中的 BLOB 所需的时间。因此,对于大于 1.0 的数字,直接将 BLOB 存储在数据库中会更快。对于小于 1.0 的数字,将 BLOB 存储在单独的文件中会更快。
在每一种情况下,都会对页缓存的大小进行调整,使缓存内存的数量保持在 2MB 左右。BLOB 值是以随机顺序读取的。
数据库页大小 | BLOB 大小 | ||||||
---|---|---|---|---|---|---|---|
10k | 20k | 50k | 100k | 200k | 500k | 1m | |
1024 | 1.535 | 1.020 | 0.608 | 0.456 | 0.330 | 0.247 | 0.233 |
2048 | 2.004 | 1.437 | 0.870 | 0.636 | 0.483 | 0.372 | 0.340 |
4096 | 2.261 | 1.886 | 1.173 | 0.890 | 0.701 | 0.526 | 0.487 |
8192 | 2.240 | 1.866 | 1.334 | 1.035 | 0.830 | 0.625 | 0.720 |
16384 | 2.439 | 1.757 | 1.292 | 1.023 | 0.829 | 0.820 | 0.598 |
32768 | 1.878 | 1.843 | 1.296 | 0.981 | 0.976 | 0.675 | 0.613 |
65536 | 1.256 | 1.255 | 1.339 | 0.983 | 0.769 | 0.687 | 0.609 |
从上面的矩阵中可以得出以下结论:
- 数据库页面大小为 8192 或 16384 时,大型 BLOB 的 I/O 性能最好。
- 对于小于 100KB 的 BLOB,当 BLOB 直接存储在数据库文件中时,读取速度会更快。
- 对于大于 100KB 的 BLOB,从一个单独的文件中读取会更快。
与使用 fread() 或 fwrite() 从磁盘上读取或写入单个文件相比,SQLite 读取和写入小型 BLOB (例如,缩略图)的速度快 35%。
此外,一个包含 10KB BLOB 的 SQLite 数据库所使用的磁盘空间比将这些 BLOB 存储在单个文件中要少大约 20%。
性能差异的产生(我认为)是因为当使用 SQLite 数据库时,open() 和 close() 只被调用一次。而当使用存储在单个文件中的 BLOB 时,open() 和 close() 对每个 BLOB 均需调用。看来,调用 open() 和 close() 的开销要比使用数据库的开销大。
大小的减少是由于单个文件被填充到文件系统块大小的下一个倍数,而 BLOB 则被更紧密地包装在 SQLite 数据库中。