Perl:在磁盘上存储巨大的哈希有问题吗?

Posted

技术标签:

【中文标题】Perl:在磁盘上存储巨大的哈希有问题吗?【英文标题】:Perl: Trouble storing a huge hash on disk? 【发布时间】:2014-02-14 01:44:56 【问题描述】:

我正在从事一个 Perl 项目,该项目涉及使用大约 1700 万个键构建散列。这太大了,无法存储在内存中(我的笔记本电脑的内存只能保存大约 1000 万个键)。我知道解决方案是将数据存储在磁盘上,但在实践中我无法执行此操作。这是我尝试过的:

DB_File

use strict;
use DB_File;
my $libfile = shift;
my %library;
tie %library, "DB_File", "$libfile";
for (my $a = 1; $a < 17000000; a++) 
    # Some code to generate key and value #
    $library$key = $value;

这给了我一个分段错误:循环中的 11 部分,原因我不明白。

伯克利数据库

use strict; 
use BerkeleyDB;
my $libfile = shift;
my $library = new BerkeleyDB::Hash
    -Filename => $libfile,
    -Flags => DB_CREATE;

for (my $a = 1; $a < 17000000; a++) 
    # Some code to generate key and value #
    $library->db_put($key, $value);

这对于前 1500 万个键似乎效果很好,但随后会显着减慢并最终在循环结束时完全冻结。我认为这不是内存问题。如果我将循环分成四部分,将它们放在四个单独的程序中,并按顺序运行它们(每次向数据库添加约 400 万条记录),前三个成功完成,但第四个在数据库大约有 15 条时挂起万把钥匙。所以看起来 BerkeleyDB 可能只能处理大约 1500 万个哈希键???

DBM::Deep

use strict; 
use DBM::Deep;
my $libfile = shift;
my $library = new DBM::Deep $libfile;

for (my $a = 1; $a < 17000000; a++) 
    # Some code to generate key and value #
    $library->put($key => $value);

从初步测试来看,这似乎工作正常,但它真的很慢:每千个键大约 5 秒,或者运行整个循环约 22 小时。如果可能的话,我宁愿避免这种情况。

我将非常感谢有关解决其中一个软件包的建议,或有关完成相同任务的其他选项的想法。

更新

【问题讨论】:

看看使用 mongodb 之类的 nosql 数据库是否适合您。 mongodb.com/learn/nosql 什么操作系统和 perl 版本以及您尝试过的模块?您的平均键和平均值有多大? 你能在“key sorted”模式下生成条目吗?我想我记得一个巨大的 BerkeleyDB 案例,当从散列切换到 btree 时,“键排序”插入提高了性能。改进非常显着,但还不够。 @AndrzejA.Filip:使用 Btree 就可以了。谢谢!!! 在报告的情况下,我记得巨大的 BerkeleyDB 创建时间从哈希的几个小时减少到带有“键排序”附加的 btree 的 20 分钟。反正时间太长了,所以这个家伙决定切换到能够直接访问 SQL 数据库的软件,以避免将 SQL 数据库“转储”到 BerkeleyDB。 【参考方案1】:

切换到 btree 可以提高以“键排序模式”访问的 HUGE BerkeleyDB 的性能。它减少了所需的磁盘 I/O 操作次数。

案例研究: 在新闻报道的一个案例中:comp.mail.sendmail 我记得巨大的 BerkeleyDB 创建时间从哈希的几个小时减少到带有“键排序”附加的 btree 的 20 分钟。无论如何它太长了,所以这个家伙决定切换到能够直接访问 SQL 数据库的软件,从而避免将 SQL 数据库“转储”到 BerkeleyDB。 (virtusertable, sendmail->postfix)

【讨论】:

【参考方案2】:

你可以试试 PostgreSQL。

先创建一个有两列key和value的表,varchar就可以了,

然后,不要插入每一个,而是使用 Pg::BulkCopy 将数据复制到数据库。

我建议一次插入不超过 100 MB,因为当您的 COPY 命令失败时,PostgreSQL 会将之前插入的那些行保留在磁盘上,并且只有在您 VACUUM FULL 表时才会将其删除。 (有一次我处理了很多 5GB,其中一些由于几乎结束的一些限制而失败,并且磁盘在回滚时永远不会恢复..)

ps:你也可以直接使用 DBD::Pg:https://metacpan.org/pod/DBD::Pg#COPY-support

所有复制完成后,您可以在 key 上创建索引,如果您需要更快的速度,请使用 Redis 或带有 MAXMEMORY POLICY 的 memcached

【讨论】:

以上是关于Perl:在磁盘上存储巨大的哈希有问题吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Perl SDK 将额外数据存储上的 VMFS5 磁盘添加到 VM

在 Perl 中,哈希键周围的引号是一种好习惯吗?

如何在 Perl 中获取哈希的一部分?

如何解析具有特定格式数据的文本文件并使用 perl 将其存储在哈希中

如何在 Perl 哈希表中存储多个值?

如何将数组作为值存储在 Perl 哈希中?