从文件还是数据库服务器访问数据更快?

75
如果我有一个由文件夹和文件组成的静态数据库,考虑到这将在CGI脚本中使用,那么访问和操作是否比SQL服务器类型的数据库更快?
在处理文件和文件夹时,如何提高性能?

这个问题是基于观点的——因为你无法衡量不同实现模型下操作运行所需的时间。你甚至无法近似计算。这完全是主观观点,没有任何实际依据。 - NeilG
这个问题是基于观点的,因为你无法衡量不同实现模型下操作运行的时间。你甚至无法近似地估计。这只是观点而已,没有现实依据。 - undefined
13个回答

75

我也会说“要看具体情况而定”。

这是一种没有通用答案的问题,而是严重依赖于实际情况。我最近甚至将一些数据从 SQL 数据库移动到了平面文件系统中,因为数据库的开销加上一些数据库连接可靠性问题,使得使用平面文件成为更好的选择。

在做出选择时,我会问自己一些问题,包括:

  1. 我如何消费数据?例如,我只会按输入顺序从开始到结束行读取吗?还是我会搜索匹配多个标准的行?

  2. 在一个程序执行期间,我会经常访问数据吗?我会一次去获取所有 Salinger 作为作者的书籍,还是我会多次去获取几个不同的作者?我会因为多个条件而多次访问吗?

  3. 我将如何添加数据?我可以只追加一个行到结尾,这对我的检索来说很完美,还是它需要重新排序?

  4. 代码在六个月后看起来有多合理?我强调这一点,因为我认为在设计东西时(不仅仅是代码,这个摇马是实际来自我在海军当机械师时诅咒机械工程师的日子里)这太容易被忽视了。六个月后,当我必须维护你的代码(或者你在另一个项目上工作之后)时,哪种存储和检索数据的方式会更有意义?如果从平面文件转换到数据库可以提高 1% 的效率,但在更新代码时需要花费一周的时间来解决问题,那么你真的改进了什么。


30
你能否添加一下你会使用哪个工具?看起来模式是:如果问题的第一部分为“是”,则使用文件,如果是第二部分,则使用数据库,但我不确定。 - mbigras
1
  1. 如果需要从头到尾读取,请使用平面文件。
  2. 如果只需一次获取所有图书,请使用平面文件。
  3. 如果追加操作可行,请使用平面文件。
- Janac Meena

35

一般而言,数据库比文件慢。

如果您需要对文件进行索引,则在自定义索引结构上硬编码的访问路径始终具有更快的潜力(如果正确执行)。

但是,选择数据库而不是基于文件的解决方案时,“性能”并不是目标。

您应该问自己是否需要数据库提供的任何好处。如果是这样,那么小的性能开销是可以接受的。

所以:

  1. 您是否需要处理多个用户和并发更新?(好吧;您说它是静态的。)
  2. 您是否需要灵活性以便从各个角度轻松查询数据?
  3. 您是否有多个用户,并且可以利用现有的安全模型?

基本上,问题更多地是哪个更容易开发。两者之间的性能差异不值得浪费开发时间。


3
我想补充一点,性能优势只有在你知道自己在做什么的情况下才存在。创建一个好的、快速的索引方案并不容易。即使是数据通用的数据库,它们也经过了几年的算法优化。我认识的大多数人试图用平面文件打败数据库都失败了。但是有些人成功了,适用于你需要的罕见情况。 - mpeters
如果你在运行lambda函数,启动时间非常关键。有一些方法可以保持lambda函数的热启动,但它们并不有效,并且比你想象的更难实施。如果你有大量静态数据,并且只想在进程结束之前读取其中的一小部分,启动数据库是行不通的。而使用平面文件则可行。往往很难在没有带入你从“正常”场景中所拥有的所有先入为主观念的情况下评估这类问题。 - NeilG
如果你在运行lambda函数,启动时间就非常关键。有一些方法可以保持lambda函数的热启动,但它们并不有效,并且比你想象的更难实现。如果你有大量的静态数据,并且只想在进程结束之前读取其中的一小部分,启动一个数据库来完成这个任务是行不通的。而使用平面文件则是可行的。在没有带入你从“正常”场景中所持有的所有先入为主的观念的情况下,评估这类问题通常是困难的。 - undefined

26

根据您的信息和访问模式以及规模不同,使用关系数据库的两个最大好处是:

  1. 缓存。除非您很聪明,否则您无法编写一个像DB服务器那样好的缓存。

  2. 优化器。

然而,对于某些专业应用程序,与文件夹数据存储相比,这两种好处都没有得到体现 - 因此答案是“取决于情况”。

至于文件/文件夹,技巧如下:

  • 缓存经常请求的文件内容
  • 拥有小目录(深度嵌套的小目录中的文件比平坦结构中的文件更快地访问,因为读取大目录内容所需的时间更长)。
  • 还有其他更高级的优化(跨磁盘切片、放置在磁盘或不同分区的不同位置等) - 但如果您需要达到那个程度,最好一开始就使用数据库。

9
我不完全同意你写的内容:1) 在数据库服务器上缓存必须是通用的。如果你编写自己的应用程序特定的缓存系统,你应该能够轻松胜任。2) 优化器 - 再次强调,优化器必须是通用的;有了特定的应用程序知识,您可以编写更高效的访问路径,并利用通常RDBMS索引选项中不可用的结构。3) 如果您有文件的完整路径,大目录只有在需要“搜索”文件时才会变慢;此时您将不需要“读取大目录的内容”。 - Disillusioned
3
@Craig - 我不知道他的使用模式和数据。因此你的观点可能有效也可能无效 - 这取决于具体情况。但是,你自定义的文件结构是否知道如何将最常用的数据放在磁盘较快的区域?你是否擅长编写良好的高速缓存机制?这就是我说“这要看情况”的原因 - 如果不知道他应用程序的详细信息,我就不能就如何编写适合他需求的自定义文件结构来替代数据库发表任何判断。 - DVK
2
@DVK:你不需要知道他的使用模式是什么,重点是他知道(或应该知道),而他的应用程序特定知识使得编写更好的缓存成为可能。当你拥有“主场优势”时,你不必非常聪明就能编写出良好的缓存。问题涉及一般性能差异:一个实现不良的数据库与一个实现不良的基于文件的解决方案一样糟糕。但是,一个实现良好的基于文件的解决方案将优于一个实现良好的数据库解决方案(但在开发时间上成本要高得多)。 - Disillusioned
1
@Sinan - 我被 mod_perl 宠坏了 - 它消除了启动速度的库负载和编译惩罚。 - DVK
@DVK 我知道 mod_perl 的优点。然而,问题明确指出了一个 CGI 环境。 - Sinan Ünür
显示剩余4条评论

14

从我的一点经验来看,基于服务器的数据库(即使是在本地机器上提供的)与本地文件系统相比,吞吐量往往非常慢。然而,这取决于一些因素,其中之一是渐近复杂度。将扫描大量文件与使用带有索引的数据库查找项目进行比较,数据库胜出。

我的一点经验是关于PostgreSQL的。我有一个包含三百万行记录的表格,我要更新仅8,000条记录。这花了8秒钟。

至于“过早优化是万恶之源”的引用,我会抱着怀疑的态度看待它。如果您使用数据库编写应用程序,发现它很慢,那么切换到基于文件系统的方法或其他方法(例如SQLite)可能需要大量时间。我认为最好的方法是创建一个非常简单的工作负载原型,并使用这两种方法进行测试。我认为了解哪个更快在这种情况下非常重要。


7

正如其他人指出的那样:这取决于具体情况!

如果你真正需要弄清楚哪种格式更适合你的性能需求,你可能需要生成一些示例数据以存储在每种格式中,然后运行一些基准测试。Benchmark.pm模块附带在Perl中,并且可以很容易地进行类似以下内容的并排比较:

use Benchmark qw(:all) ;

my $count = 1000;  # Some large-ish number of trials is recommended.

cmpthese($count, {
    'File System' => sub { ...your filesystem code... },
    'Database'    => sub { ...your database code... }
});

您可以输入 perldoc Benchmark 以获取更完整的文档。

4

如果网站结构适合,使用文件而不是数据库来处理图片非常有用。创建代表匹配数据的文件夹,并将图像放入其中。例如,您拥有一家文章网站,将文章存储在数据库中。您不必在数据库中放置图像路径,可以将文件夹命名为您的主键(如1、2、3..),并将图像放入其中。电子书、音乐文件、视频等媒体文件均可使用此方法。如果您不需要搜索任何内容,则可以使用相同的逻辑来处理XML文件。


4

数据库确实可以更快

引用SQLite的测试结果,

与使用fread()或fwrite()从磁盘上的单个文件中读取或写入相同的小块数据(例如缩略图)相比,SQLite读取和写入小块数据的速度要快35%¹。

此外,一个包含10千字节的小块数据的单个SQLite数据库所需的磁盘空间约少20%,而不是将这些小块数据存储在单独的文件中。

性能差异之所以出现(我们认为)是因为当从SQLite数据库中工作时,只调用一次open()和close()系统调用,而在使用存储在单独文件中的小块数据时,对于每个小块数据都会分别调用open()和close()。看起来,调用open()和close()的开销大于使用数据库的开销。大小减少是由于单独的文件被填充到下一个文件系统块大小的倍数,而小块数据则更紧密地打包到SQLite数据库中。

本文中的测量是在2017-06-05这一周内使用版本介于3.19.2和3.20.0之间的SQLite进行的。您可以期望未来的SQLite版本表现得更好。


3

像其他人所说,数据库是一个工具,它会带来一些开销,但是如果你的数据是静态的,并且是只读数据,直接从文件夹中读取文件将更快:

以下是我进行的一些测试:

我的文件名为 .csv 文件

在数据库中,我将“日期”作为索引列,以便在数据库中查找相同的记录。每天有 30K-50K 条记录/行,100 列不同类型的数据(90% 浮点数)。

数据库信息:

PostgreSQL 11.5,16GB 的 RAM

  Table:
    335,162,867 records
    Table size: 110GB
    Index size: 7GB
    Total size: 117GB
  Files:
    Number of files: 8033
    Total Files size: 158GB
    Number of records/lines per file/date: 30K - 50K

从文件中读取随机日期(1986-2019)的数据比在PostgreSQL中读取相同日期的数据快4-5倍。

2
为了快速访问文件,根据您正在做什么,mmap 可能非常方便。我在Effective Perl博客中写了一篇文章,介绍了内存映射文件而不是将它们读入内存
然而,我认为数据库服务器会更快。当我们不知道您正在做什么、需要访问什么样的数据等时,很难确定哪种方法对您来说更快。

2

这取决于数据的特点以及您将使用何种逻辑来访问它。如果您只需要保存和提取命名节点,则基于文件系统的数据库可能更快且更有效率。(您也可以考虑使用Berkeley DB实现此目的。)如果您需要进行基于索引的搜索,尤其是如果您需要根据键连接不同数据集,则SQL数据库是最佳选择。

我建议您选择对于您的应用程序最自然的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接