在处理文件和文件夹时,如何提高性能?
我也会说“要看具体情况而定”。
这是一种没有通用答案的问题,而是严重依赖于实际情况。我最近甚至将一些数据从 SQL 数据库移动到了平面文件系统中,因为数据库的开销加上一些数据库连接可靠性问题,使得使用平面文件成为更好的选择。
在做出选择时,我会问自己一些问题,包括:
我如何消费数据?例如,我只会按输入顺序从开始到结束行读取吗?还是我会搜索匹配多个标准的行?
在一个程序执行期间,我会经常访问数据吗?我会一次去获取所有 Salinger 作为作者的书籍,还是我会多次去获取几个不同的作者?我会因为多个条件而多次访问吗?
我将如何添加数据?我可以只追加一个行到结尾,这对我的检索来说很完美,还是它需要重新排序?
代码在六个月后看起来有多合理?我强调这一点,因为我认为在设计东西时(不仅仅是代码,这个摇马是实际来自我在海军当机械师时诅咒机械工程师的日子里)这太容易被忽视了。六个月后,当我必须维护你的代码(或者你在另一个项目上工作之后)时,哪种存储和检索数据的方式会更有意义?如果从平面文件转换到数据库可以提高 1% 的效率,但在更新代码时需要花费一周的时间来解决问题,那么你真的改进了什么。
一般而言,数据库比文件慢。
如果您需要对文件进行索引,则在自定义索引结构上硬编码的访问路径始终具有更快的潜力(如果正确执行)。
但是,选择数据库而不是基于文件的解决方案时,“性能”并不是目标。
您应该问自己是否需要数据库提供的任何好处。如果是这样,那么小的性能开销是可以接受的。
所以:
基本上,问题更多地是哪个更容易开发。两者之间的性能差异不值得浪费开发时间。
根据您的信息和访问模式以及规模不同,使用关系数据库的两个最大好处是:
缓存。除非您很聪明,否则您无法编写一个像DB服务器那样好的缓存。
优化器。
然而,对于某些专业应用程序,与文件夹数据存储相比,这两种好处都没有得到体现 - 因此答案是“取决于情况”。
至于文件/文件夹,技巧如下:
mod_perl
的优点。然而,问题明确指出了一个 CGI
环境。 - Sinan Ünür从我的一点经验来看,基于服务器的数据库(即使是在本地机器上提供的)与本地文件系统相比,吞吐量往往非常慢。然而,这取决于一些因素,其中之一是渐近复杂度。将扫描大量文件与使用带有索引的数据库查找项目进行比较,数据库胜出。
我的一点经验是关于PostgreSQL的。我有一个包含三百万行记录的表格,我要更新仅8,000条记录。这花了8秒钟。
至于“过早优化是万恶之源”的引用,我会抱着怀疑的态度看待它。如果您使用数据库编写应用程序,发现它很慢,那么切换到基于文件系统的方法或其他方法(例如SQLite)可能需要大量时间。我认为最好的方法是创建一个非常简单的工作负载原型,并使用这两种方法进行测试。我认为了解哪个更快在这种情况下非常重要。
正如其他人指出的那样:这取决于具体情况!
如果你真正需要弄清楚哪种格式更适合你的性能需求,你可能需要生成一些示例数据以存储在每种格式中,然后运行一些基准测试。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
以获取更完整的文档。如果网站结构适合,使用文件而不是数据库来处理图片非常有用。创建代表匹配数据的文件夹,并将图像放入其中。例如,您拥有一家文章网站,将文章存储在数据库中。您不必在数据库中放置图像路径,可以将文件夹命名为您的主键(如1、2、3..),并将图像放入其中。电子书、音乐文件、视频等媒体文件均可使用此方法。如果您不需要搜索任何内容,则可以使用相同的逻辑来处理XML文件。
引用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版本表现得更好。
像其他人所说,数据库是一个工具,它会带来一些开销,但是如果你的数据是静态的,并且是只读数据,直接从文件夹中读取文件将更快:
以下是我进行的一些测试:
我的文件名为 .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
这取决于数据的特点以及您将使用何种逻辑来访问它。如果您只需要保存和提取命名节点,则基于文件系统的数据库可能更快且更有效率。(您也可以考虑使用Berkeley DB实现此目的。)如果您需要进行基于索引的搜索,尤其是如果您需要根据键连接不同数据集,则SQL数据库是最佳选择。
我建议您选择对于您的应用程序最自然的解决方案。