在badgerDB中,我们有数以十亿计的string类型的键和HashValueList类型的值。在我们的用例中,HashValueList的长度可能是数百万。在插入到[]byte之前,我们必须在BadgerDb中对键和值进行编码;我们使用的是encoding/gob包。因此,每当我们需要价值时,我们必须再次解码它们。在我们的例子中,这个解码过程正在造成开销。
type HashValue struct {
Row_id string
Address string
}
type HashValueList []HashValue为了减少解码开销,我们将设计更改为前缀迭代。使用前缀迭代,我们将集合中的每个值存储为一个不同的Badger KV对,而不是一个大值的单个键。键的前缀将是原始哈希值键。然后,我们需要添加一个后缀,以提供来自原始集合的值集合的唯一性。所以在你最初的计划中有这样的东西:
k1 -> [v1, v2, v3, ..., vn]
...
km -> [w1, ..., wm]现在有这样的东西:
k1@1 -> v1
k1@2 -> v2
k1@3 -> v2
...
k1@n -> vn
...
km@1 -> w1
...
km@m -> wm为了从DB中找到值,我们有n个goroutines读取KeyChan通道并将值写入ValChan。
func Get(db *badger.DB, KeyChan <-chan string, ValChan chan []byte) {
var val []byte
for key := range KeyChan {
txn := db.NewTransaction(false)
opts := badger.DefaultIteratorOptions
opts.Prefix = []byte(key)
it := txn.NewIterator(opts)
prefix := []byte(key)
for it.Rewind(); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
val, err := item.ValueCopy(val[:])
ValChan <- val
item = nil
if err != nil {
fmt.Println(err)
}
}
it.Close()
txn.Discard()
}
}在前缀迭代中,让func在一段时间后变得非常慢。我们收集了一个5秒钟的执行跟踪,结果如下:

在这里,github.com/dgraph-io/badger/v3.(*Iterator).fill.func1 N=2033535在内部创建了大量的Goroutine。


在调度器中花费的大量时间。
如何提高前缀迭代性能?我们的用例有什么更好的方法吗?
谢谢
发布于 2022-03-17 12:41:20
如果您想要非常快地遍历前缀并收集结果,那么应该考虑在Badger中使用Stream框架。它使用许多goroutines来使迭代速度达到磁盘允许的速度。
https://pkg.go.dev/github.com/outcaste-io/badger/v3#Stream
此外,一般来说,使用围棋频道收集可能是数百万的结果将是非常缓慢的。使用通道的最佳方法是分批处理结果并减少与它们交互的次数。
流框架通过为您提供一个串行执行的Stream.Send函数来处理所有这些问题。您甚至可以将编码的数据保持原样,并在发送中对其进行解码,或者将其复制到发送中。
https://stackoverflow.com/questions/71510489
复制相似问题