维护一个大于内存的排序列表

时间:2010-05-31 14:37:36

标签: algorithm memory sorting

我有一个元组列表。

[
  "Bob": 3,
  "Alice": 2,
  "Jane": 1,
]

递增计数

 "Alice" += 2

应保持订单:

[
  "Alice": 4,
  "Bob": 3,
  "Jane": 1,
]

当所有内容都在内存中时,有效的方法(更多或更少)可以有效地实现它。 (使用索引,插入排序等)问题是:当列表不适合内存时,最有前途的方法是什么。

奖金问题:即使指数不适合记忆,该怎么办?

你会怎么做?

9 个答案:

答案 0 :(得分:7)

MySQL之类的关系数据库专门用于存储大量数据,这些数据的总和不适合内存,查询大量数据,甚至更新数据。

例如:

CREATE TABLE `people` (
    `name`    VARCHAR(255),
    `count`   INT
);

INSERT INTO `people` VALUES
('Bob', 3),
('Alice', 2),
('Jane', 1);

UPDATE `people` SET `count` = `count` + 2;

UPDATE语句后,查询SELECT * FROM people;将显示:

+-------+-------+
| name  | count |
+-------+-------+
| Bob   |     5 |
| Alice |     4 |
| Jane  |     3 |
+-------+-------+

您可以通过添加自动增量主键来保存表格中的人员顺序:

people

答案 1 :(得分:7)

B+ trees使用密钥订购多个项目。在这种情况下,键是计数,项目是人的名字。整个B +树不需要适合内存 - 只需要搜索当前节点。您可以设置节点的最大大小(以及间接树的深度),以便节点适合内存。 (实际上,节点通常远小于内存容量。)

数据项存储在树的叶子中,即所谓的块中。您可以将项目内联存储在索引中,也可以存储指向外部存储的指针。如果数据是规则大小的,这可以有效地从文件中检索。在问题示例中,数据项可以是单个名称,但是存储名称块会更有效,所有名称都在具有相同计数的块中。每个块中的名称也可以进行排序。 (块中的名称本身可以组织为B树。)

如果名称的数量变得足够大以致B +树块变得非常大,则可以将密钥制成复合密钥,例如,密钥。 (伯爵,第一个字母)。搜索树时,只需要比较计数以查找具有该计数的所有名称。插入或搜索具有给定计数的特定名称时,可以比较完整密钥以包括按名称前缀过滤。

或者,数据项可以指向包含名称块的外部文件中的偏移/块,而不是复合键,这将使B +树本身保持较小。

如果btree的块链接在一起,则可以通过搜索范围的开始,然后跟随指向下一个块的块指针直到达到范围的结尾来有效地实现范围查询。这将允许您有效地实现“查找计数在10到20之间的所有名称”。

正如其他答案所指出的那样,RDBMS是存储不适合内存的列表的预先打包方式,但我希望这可以深入了解用于解决问题的结构。

答案 2 :(得分:1)

RDMS?甚至像SQLite这样的平面文件版本。否则使用延迟加载的组合。只保留X记录在内存中的前Y个记录&最新的Z计数更新了。否则,您运行UPDATE更改值的Key,Count列表。可以使用简单的SELECT ORDER BY检索有序列表。

答案 3 :(得分:1)

了解B树和B +树。有了这些,索引总是可以做得足够小,以适应内存。

答案 4 :(得分:1)

与BTrees完全不同的有趣方法是Judy Tree

答案 5 :(得分:1)

您似乎要寻找的容器类out of core algorithms,特别是核心列表容器类。查看stxxl库,了解核心算法和处理的一些很好的例子。

您可能还想查看this相关问题

答案 6 :(得分:0)

就“手工处理此问题的实施细节”而言,您可以通过搜索有关数据库设计的原始论文或查找有关数据库架构的研究生课程笔记来了解数据库系统如何做到这一点。

我做了一些搜索,发现了G. Graefe的一篇名为“Query evaluation techniques for large databases”的调查文章。它有点详尽地涵盖了查询大型数据库的各个方面,但整个第4节阐述了“查询评估系统......如何访问存储在数据库中的基础数据”。此外,Graefe的调查与2001年秋季在杜克的CPS 216:高级数据库系统的课程页面相关联。第5周是Physical Data Organization,其中说大多数商业DBMS使用N中的块来组织磁盘上的数据ary存储模型(NSM):记录从每个块的开头存储,最后存在“目录”。

另见:

答案 7 :(得分:0)

  

当然我知道我可以使用数据库。这个问题更多的是关于解决这个“手工”的实施细节

所以基本上,你问“数据库如何做到这一点?”答案是,它使用一棵树(对于数据和索引),并且只存储部分任何时候记忆中的树。

正如已经提到的,B-Trees对此特别有用:因为硬盘驱动器总是一次读取固定数量(“扇区大小”),你可以制作每个节点一个扇区的大小,以最大限度地提高效率。

答案 8 :(得分:0)

您没有指定需要添加或删除列表中的任何元素,只需对其进行排序。

如果是这样,一个简单的平面文件方法 - 通常使用mmap方便 - ,并且比更通用的数据库更快。

您可以使用bsearch找到该项目,或使用每个值维护一组时段数。

当您访问某个项目时,它所在的文件部分(根据内存“页面”)会被操作系统自动读入RAM,并且插槽及其相邻的插槽甚至会被复制到L1中高速缓存行。

您可以对其相邻的插槽进行即时比较,以查看增量或减量是否导致项目无序;如果是,您可以使用线性迭代(可能使用bsearch进行扩充)来找到具有适当计数的第一个/最后一个项目,然后交换它们。

管理文件是操作系统的基础。