为什么与使用迭代器相比,大型键集的 Get 和 MultiGet 明显慢

Why are Get and MultiGet significantly slower for large key sets compared to using an Iterator?

本文关键字:Get MultiGet 大型 迭代器 为什么      更新时间:2023-10-16

我目前正在玩RocksDB (C++),并对我经历过的一些性能指标感到好奇。

出于测试目的,我的数据库键是文件路径,值是文件名。我的数据库中有大约 2M 个条目。我在MacBook Pro 2016(SSD)上本地运行RocksDB。

我的用例以读取为主。完整密钥扫描很常见,包含"大量"密钥的密钥扫描也很常见。(50%+)

我对以下观察结果感到好奇:

1. 执行完整密钥扫描时,Iterator比调用Get要快得多。

当我想查看数据库中的所有键时,我看到使用Iterator而不是为每个键调用Get时性能提高了 4-8 倍。使用MultiGet没有区别。

在调用Get大约 2M 次的情况下,键之前已被提取到向量中并按字典顺序排序。为什么反复调用Get比使用Iterator慢得多?有没有办法缩小两个 API 之间的性能差距?

2. 当获取大约一半的键时,使用IteratorGet之间的性能开始变得可以忽略不计。

随着要获取的密钥数量的减少,对Get进行多次调用开始花费与使用Iterator的时间一样长,因为迭代器正在支付扫描不在所需密钥集中的密钥的代价。

对于大多数数据库来说,是否有一些"魔术"比率变得如此?例如,如果我需要扫描超过 25% 的键,则调用Get会更快,但如果是 75% 的键,则Iterator会更快。但这些数字只是通过粗略的测试"弥补"出来的。

3. 按排序顺序获取键似乎不会提高性能。

如果我对要获取的键进行预排序,其顺序与Iterator返回的顺序相同,这似乎不会使调用Get多次的速度更快。为什么?文档中提到,建议在执行批处理插入之前对键进行排序。Get不会从Iterator从中受益的相同前瞻缓存中受益吗?

4. 对于读取密集型用例,建议进行哪些设置?

最后,对于可能涉及一次扫描大量密钥的读取密集型用例,是否建议使用任何特定设置?

macOS 10.14.3, MacBook Pro 2016 SSD, RocksDB 5.18.3, Xcode 10.1

RocksDB 在内部将其数据表示为一个日志结构的合并树,默认情况下它有几个排序层(这可以通过插件/配置进行更改)。保罗第一个答案的直觉成立,除了没有经典索引;数据实际上是在磁盘上排序的,并带有指向下一个文件的指针。查找操作具有平均对数复杂度,但在排序范围内推进迭代器是恒定时间。因此,对于密集的顺序读取,迭代要快得多。

成本平衡的点不仅取决于读取的密钥数,还取决于数据库的大小。随着数据库的增长,查找速度变慢,而Next()保持不变。最近的插入可能会很快被读取,因为它们可能仍在内存中(内存表)。

对键进行排序实际上只会提高缓存命中率。根据您的磁盘,差异可能非常小,例如,如果您有 NVMe SSD,则访问时间的差异不再像 RAM 与 HDD 时那样剧烈。如果你必须对相同甚至不同的键集执行多个操作,则按键顺序(f(a-c) g(a-c) f(d-g)...)而不是按顺序执行这些操作应该可以提高性能,因为您将有更多的缓存命中率,并且还可以从RocksDB块缓存中受益。

调优指南是一个很好的起点,尤其是有关数据库解决方案的视频,但如果 RocksDB 对您来说太慢,也可以考虑使用基于不同存储算法的数据库。LSM 通常更适合写入头型工作负载,虽然 RocksDB 可以让您很好地控制读取、写入和空间放大,但基于 b 树或 ISAM 的解决方案对于范围读取/重复读取可能要快得多。

我对RocksDB本身一无所知,但我可以从第一原则回答很多问题。

执行完整密钥扫描时,迭代器比调用 Get 快得多。

这可能是因为Get必须在底层索引中进行全面查找(从顶部开始),而推进迭代器只需从当前节点移动到下一个节点即可实现。 假设索引实现为红黑树或类似方法,则第二种方法的工作比第一种方法少得多。

当获取大约一半的键时,使用迭代器和 Get 之间的性能开始变得可以忽略不计。

所以你通过多次调用iterator->Next ()来跳过条目? 如果是这样,那么总有一天,为每个密钥调用Get更便宜,是的。 确切的时间将取决于索引中的条目数(因为这决定了树中的级别数)。

按排序顺序提取键似乎不会提高性能。

不,我不希望它。Get(大概)是无国籍的。

对于读取密集型用例,建议进行哪些设置?

我不知道,对不起,但你可能会读到:

https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide