删除范围键

注意: 本页描述的技术已经过时,对于RocksDB 5.18+的用户,对于所有已知的用例,本地的DeleteRange函数是更好的选择。

在多数情况下,人们希望删除范围键。例如,在MyRocks中,我们通过添加表ID前缀对一个表中的行进行编码,因此当我们需要删除一个表时, 需要删除所有带有前缀的键。另一个例子是,如果我们用[user_id][attribute_id]格式存储带键用户的不同属性,那么如果用户删除账户, 我们需要删除前缀为[user_id]的所有键。

删除这些键的标准方法是遍历所有键并逐个发出Delete()。当要删除的键数不大时,此方法可以工作。然而,这种解决方案有两个潜在的缺点:

  1. 1.数据占用的空间不会被立即回收。我们将等待压缩来清理数据。当要删除的范围占用数据库的大量空间时,这通常是一个问题。
  2. 2.墓碑块可能会减慢迭代器的速度。

还有两种方法可以从范围中删除键:

第一种方法是向该范围发出DeleteFilesInRange()。该命令将删除所有只包含要删除范围内的键的SST文件。对于一个大的块,它会立即回收大部分空间,所以这是第1题的一个很好的解决方案。 需要注意的一件事是,在操作之后,范围中的一些键可能仍然存在于数据库中。如果您想删除所有这些操作,您应该继续进行其他操作,但是可以以较慢的速度完成。 另外,请注意,尽管存在快照,DeleteFilesInRange()仍将被删除,因此您不应该再期望能够使用现有快照从该范围读取数据。

另一种方法是与CompactRange()一起应用压缩过滤器。您可以编写一个压缩过滤器,它可以从已删除的范围中过滤出键。 如果要从范围中删除键,请调用CompactRange()来删除范围。当压缩完成时,键将被删除。我们建议您将CompactionFilter::IgnoreSnapshots()设置为true,以确保即使您有出色的快照,也会删除键。 否则,您可能无法从系统中完全删除范围内的所有键。这种方法还可以解决数据回收的问题,但是它比DeleteFilesInRange()方法引入了更多的I/O。但是,DeleteFilesInRange()不能删除该范围内的所有数据。因此,更好的方法是首先应用DeleteFilesInRange(),然后使用压缩过滤器发出CompactRange()。

问题2是一个更难解决的问题。一种方法是应用DeleteFilesInRange() + CompactRange(),以便删除该范围的所有键和tombstones。它适用于大范围,但如果我们频繁地降低小范围,它就成本太高了,原因是DeleteFilesInRange()不太可能删除任何文件,而CompactRange()将删除比需要多得多的数据, 因为它需要对删除范围中包含任何键的所有SST文件执行压缩。对于CompactRange()过于昂贵的用例,仍然有两种方法可以减少危害:

  1. 1.如果您从未覆盖过现有的键,您可以尝试使用DB::SingleDelete()而不是Delete()来更快地杀死tombstones
  2. 墓碑将在遇到原始键之后被删除,而不是压缩到最后一层。
  3. 2.使用NewCompactOnDeletionCollectorFactory()在有墓碑块时加快压缩。